GL = ( function() {
	/**
	 * @fileoverview gl-matrix - High performance matrix and vector operations for WebGL
	 * @author Brandon Jones
	 * @author Colin MacKenzie IV
	 * @version 1.3.4
	 */

	/*
	 * Copyright (c) 2012 Brandon Jones, Colin MacKenzie IV
	 *
	 * This software is provided 'as-is', without any express or implied
	 * warranty. In no event will the authors be held liable for any damages
	 * arising from the use of this software.
	 *
	 * Permission is granted to anyone to use this software for any purpose,
	 * including commercial applications, and to alter it and redistribute it
	 * freely, subject to the following restrictions:
	 *
	 *    1. The origin of this software must not be misrepresented; you must not
	 *    claim that you wrote the original software. If you use this software
	 *    in a product, an acknowledgment in the product documentation would be
	 *    appreciated but is not required.
	 *
	 *    2. Altered source versions must be plainly marked as such, and must not
	 *    be misrepresented as being the original software.
	 *
	 *    3. This notice may not be removed or altered from any source
	 *    distribution.
	 */

	// Updated to use a modification of the "returnExportsGlobal" pattern from https://github.com/umdjs/umd

	(function (root, factory) {
		if (typeof exports === 'object') {
			// Node. Does not work with strict CommonJS, but
			// only CommonJS-like enviroments that support module.exports,
			// like Node.
			module.exports = factory(global);
		} else if (typeof define === 'function' && define.amd) {
			// AMD. Register as an anonymous module.
			define([], function () {
				return factory(root);
			});
		} else {
			// Browser globals
			factory(root);
		}
	}(this, function (root) {
		"use strict";

		var glMath = {};
		(function() {
			if (typeof(Float32Array) !== 'undefined') {
				var y = new Float32Array(1);
				var i = new Int32Array(y.buffer);

				/**
				 * Fast way to calculate the inverse square root,
				 * see http://jsperf.com/inverse-square-root/5
				 *
				 * If typed arrays are not available, a slower
				 * implementation will be used.
				 *
				 * @param {Number} number the number
				 * @returns {Number} Inverse square root
				 */
				glMath.invsqrt = function(number) {
				  var x2 = number * 0.5;
				  y[0] = number;
				  var threehalfs = 1.5;

				  i[0] = 0x5f3759df - (i[0] >> 1);

				  var number2 = y[0];

				  return number2 * (threehalfs - (x2 * number2 * number2));
				};
			} else {
				glMath.invsqrt = function(number) { return 1.0 / Math.sqrt(number); };
			}
		})();

		/**
		 * @class System-specific optimal array type
		 * @name MatrixArray
		 */
		var MatrixArray = null;
		
		// explicitly sets and returns the type of array to use within glMatrix
		function setMatrixArrayType(type) {
			MatrixArray = type;
			return MatrixArray;
		}

		// auto-detects and returns the best type of array to use within glMatrix, falling
		// back to Array if typed arrays are unsupported
		function determineMatrixArrayType() {
			MatrixArray = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
			return MatrixArray;
		}
		
		determineMatrixArrayType();

		/**
		 * @class 3 Dimensional Vector
		 * @name vec3
		 */
		var vec3 = {};
		 
		/**
		 * Creates a new instance of a vec3 using the default array type
		 * Any javascript array-like objects containing at least 3 numeric elements can serve as a vec3
		 *
		 * @param {vec3} [vec] vec3 containing values to initialize with
		 *
		 * @returns {vec3} New vec3
		 */
		vec3.create = function (vec) {
			var dest = new MatrixArray(3);

			if (vec) {
				dest[0] = vec[0];
				dest[1] = vec[1];
				dest[2] = vec[2];
			} else {
				dest[0] = dest[1] = dest[2] = 0;
			}

			return dest;
		};

		/**
		 * Creates a new instance of a vec3, initializing it with the given arguments
		 *
		 * @param {number} x X value
		 * @param {number} y Y value
		 * @param {number} z Z value

		 * @returns {vec3} New vec3
		 */
		vec3.createFrom = function (x, y, z) {
			var dest = new MatrixArray(3);

			dest[0] = x;
			dest[1] = y;
			dest[2] = z;

			return dest;
		};

		/**
		 * Copies the values of one vec3 to another
		 *
		 * @param {vec3} vec vec3 containing values to copy
		 * @param {vec3} dest vec3 receiving copied values
		 *
		 * @returns {vec3} dest
		 */
		vec3.set = function (vec, dest) {
			dest[0] = vec[0];
			dest[1] = vec[1];
			dest[2] = vec[2];

			return dest;
		};

		/**
		 * Performs a vector addition
		 *
		 * @param {vec3} vec First operand
		 * @param {vec3} vec2 Second operand
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.add = function (vec, vec2, dest) {
			if (!dest || vec === dest) {
				vec[0] += vec2[0];
				vec[1] += vec2[1];
				vec[2] += vec2[2];
				return vec;
			}

			dest[0] = vec[0] + vec2[0];
			dest[1] = vec[1] + vec2[1];
			dest[2] = vec[2] + vec2[2];
			return dest;
		};

		/**
		 * Performs a vector subtraction
		 *
		 * @param {vec3} vec First operand
		 * @param {vec3} vec2 Second operand
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.subtract = function (vec, vec2, dest) {
			if (!dest || vec === dest) {
				vec[0] -= vec2[0];
				vec[1] -= vec2[1];
				vec[2] -= vec2[2];
				return vec;
			}

			dest[0] = vec[0] - vec2[0];
			dest[1] = vec[1] - vec2[1];
			dest[2] = vec[2] - vec2[2];
			return dest;
		};

		/**
		 * Performs a vector multiplication
		 *
		 * @param {vec3} vec First operand
		 * @param {vec3} vec2 Second operand
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.multiply = function (vec, vec2, dest) {
			if (!dest || vec === dest) {
				vec[0] *= vec2[0];
				vec[1] *= vec2[1];
				vec[2] *= vec2[2];
				return vec;
			}

			dest[0] = vec[0] * vec2[0];
			dest[1] = vec[1] * vec2[1];
			dest[2] = vec[2] * vec2[2];
			return dest;
		};

		/**
		 * Negates the components of a vec3
		 *
		 * @param {vec3} vec vec3 to negate
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.negate = function (vec, dest) {
			if (!dest) { dest = vec; }

			dest[0] = -vec[0];
			dest[1] = -vec[1];
			dest[2] = -vec[2];
			return dest;
		};

		/**
		 * Multiplies the components of a vec3 by a scalar value
		 *
		 * @param {vec3} vec vec3 to scale
		 * @param {number} val Value to scale by
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.scale = function (vec, val, dest) {
			if (!dest || vec === dest) {
				vec[0] *= val;
				vec[1] *= val;
				vec[2] *= val;
				return vec;
			}

			dest[0] = vec[0] * val;
			dest[1] = vec[1] * val;
			dest[2] = vec[2] * val;
			return dest;
		};

		/**
		 * Generates a unit vector of the same direction as the provided vec3
		 * If vector length is 0, returns [0, 0, 0]
		 *
		 * @param {vec3} vec vec3 to normalize
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.normalize = function (vec, dest) {
			if (!dest) { dest = vec; }

			var x = vec[0], y = vec[1], z = vec[2],
				len = Math.sqrt(x * x + y * y + z * z);

			if (!len) {
				dest[0] = 0;
				dest[1] = 0;
				dest[2] = 0;
				return dest;
			} else if (len === 1) {
				dest[0] = x;
				dest[1] = y;
				dest[2] = z;
				return dest;
			}

			len = 1 / len;
			dest[0] = x * len;
			dest[1] = y * len;
			dest[2] = z * len;
			return dest;
		};

		/**
		 * Generates the cross product of two vec3s
		 *
		 * @param {vec3} vec First operand
		 * @param {vec3} vec2 Second operand
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.cross = function (vec, vec2, dest) {
			if (!dest) { dest = vec; }

			var x = vec[0], y = vec[1], z = vec[2],
				x2 = vec2[0], y2 = vec2[1], z2 = vec2[2];

			dest[0] = y * z2 - z * y2;
			dest[1] = z * x2 - x * z2;
			dest[2] = x * y2 - y * x2;
			return dest;
		};

		/**
		 * Caclulates the length of a vec3
		 *
		 * @param {vec3} vec vec3 to calculate length of
		 *
		 * @returns {number} Length of vec
		 */
		vec3.length = function (vec) {
			var x = vec[0], y = vec[1], z = vec[2];
			return Math.sqrt(x * x + y * y + z * z);
		};

		/**
		 * Caclulates the dot product of two vec3s
		 *
		 * @param {vec3} vec First operand
		 * @param {vec3} vec2 Second operand
		 *
		 * @returns {number} Dot product of vec and vec2
		 */
		vec3.dot = function (vec, vec2) {
			return vec[0] * vec2[0] + vec[1] * vec2[1] + vec[2] * vec2[2];
		};

		/**
		 * Generates a unit vector pointing from one vector to another
		 *
		 * @param {vec3} vec Origin vec3
		 * @param {vec3} vec2 vec3 to point to
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.direction = function (vec, vec2, dest) {
			if (!dest) { dest = vec; }

			var x = vec[0] - vec2[0],
				y = vec[1] - vec2[1],
				z = vec[2] - vec2[2],
				len = Math.sqrt(x * x + y * y + z * z);

			if (!len) {
				dest[0] = 0;
				dest[1] = 0;
				dest[2] = 0;
				return dest;
			}

			len = 1 / len;
			dest[0] = x * len;
			dest[1] = y * len;
			dest[2] = z * len;
			return dest;
		};

		/**
		 * Performs a linear interpolation between two vec3
		 *
		 * @param {vec3} vec First vector
		 * @param {vec3} vec2 Second vector
		 * @param {number} lerp Interpolation amount between the two inputs
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.lerp = function (vec, vec2, lerp, dest) {
			if (!dest) { dest = vec; }

			dest[0] = vec[0] + lerp * (vec2[0] - vec[0]);
			dest[1] = vec[1] + lerp * (vec2[1] - vec[1]);
			dest[2] = vec[2] + lerp * (vec2[2] - vec[2]);

			return dest;
		};

		/**
		 * Calculates the euclidian distance between two vec3
		 *
		 * Params:
		 * @param {vec3} vec First vector
		 * @param {vec3} vec2 Second vector
		 *
		 * @returns {number} Distance between vec and vec2
		 */
		vec3.dist = function (vec, vec2) {
			var x = vec2[0] - vec[0],
				y = vec2[1] - vec[1],
				z = vec2[2] - vec[2];
				
			return Math.sqrt(x*x + y*y + z*z);
		};

		// Pre-allocated to prevent unecessary garbage collection
		var unprojectMat = null;
		var unprojectVec = new MatrixArray(4);
		/**
		 * Projects the specified vec3 from screen space into object space
		 * Based on the <a href="http://webcvs.freedesktop.org/mesa/Mesa/src/glu/mesa/project.c?revision=1.4&view=markup">Mesa gluUnProject implementation</a>
		 *
		 * @param {vec3} vec Screen-space vector to project
		 * @param {mat4} view View matrix
		 * @param {mat4} proj Projection matrix
		 * @param {vec4} viewport Viewport as given to gl.viewport [x, y, width, height]
		 * @param {vec3} [dest] vec3 receiving unprojected result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		vec3.unproject = function (vec, view, proj, viewport, dest) {
			if (!dest) { dest = vec; }

			if(!unprojectMat) {
				unprojectMat = mat4.create();
			}

			var m = unprojectMat;
			var v = unprojectVec;
			
			v[0] = (vec[0] - viewport[0]) * 2.0 / viewport[2] - 1.0;
			v[1] = (vec[1] - viewport[1]) * 2.0 / viewport[3] - 1.0;
			v[2] = 2.0 * vec[2] - 1.0;
			v[3] = 1.0;
			
			mat4.multiply(proj, view, m);
			if(!mat4.inverse(m)) { return null; }
			
			mat4.multiplyVec4(m, v);
			if(v[3] === 0.0) { return null; }

			dest[0] = v[0] / v[3];
			dest[1] = v[1] / v[3];
			dest[2] = v[2] / v[3];
			
			return dest;
		};

		var xUnitVec3 = vec3.createFrom(1,0,0);
		var yUnitVec3 = vec3.createFrom(0,1,0);
		var zUnitVec3 = vec3.createFrom(0,0,1);

		var tmpvec3 = vec3.create();
		/**
		 * Generates a quaternion of rotation between two given normalized vectors
		 *
		 * @param {vec3} a Normalized source vector
		 * @param {vec3} b Normalized target vector
		 * @param {quat4} [dest] quat4 receiving operation result.
		 *
		 * @returns {quat4} dest if specified, a new quat4 otherwise
		 */
		vec3.rotationTo = function (a, b, dest) {
			if (!dest) { dest = quat4.create(); }
			
			var d = vec3.dot(a, b);
			var axis = tmpvec3;
			if (d >= 1.0) {
				quat4.set(identityQuat4, dest);
			} else if (d < (0.000001 - 1.0)) {
				vec3.cross(xUnitVec3, a, axis);
				if (vec3.length(axis) < 0.000001)
					vec3.cross(yUnitVec3, a, axis);
				if (vec3.length(axis) < 0.000001)
					vec3.cross(zUnitVec3, a, axis);
				vec3.normalize(axis);
				quat4.fromAngleAxis(Math.PI, axis, dest);
			} else {
				var s = Math.sqrt((1.0 + d) * 2.0);
				var sInv = 1.0 / s;
				vec3.cross(a, b, axis);
				dest[0] = axis[0] * sInv;
				dest[1] = axis[1] * sInv;
				dest[2] = axis[2] * sInv;
				dest[3] = s * 0.5;
				quat4.normalize(dest);
			}
			if (dest[3] > 1.0) dest[3] = 1.0;
			else if (dest[3] < -1.0) dest[3] = -1.0;
			return dest;
		};

		/**
		 * Returns a string representation of a vector
		 *
		 * @param {vec3} vec Vector to represent as a string
		 *
		 * @returns {string} String representation of vec
		 */
		vec3.str = function (vec) {
			return '[' + vec[0] + ', ' + vec[1] + ', ' + vec[2] + ']';
		};

		/**
		 * @class 3x3 Matrix
		 * @name mat3
		 */
		var mat3 = {};

		/**
		 * Creates a new instance of a mat3 using the default array type
		 * Any javascript array-like object containing at least 9 numeric elements can serve as a mat3
		 *
		 * @param {mat3} [mat] mat3 containing values to initialize with
		 *
		 * @returns {mat3} New mat3
		 */
		mat3.create = function (mat) {
			var dest = new MatrixArray(9);

			if (mat) {
				dest[0] = mat[0];
				dest[1] = mat[1];
				dest[2] = mat[2];
				dest[3] = mat[3];
				dest[4] = mat[4];
				dest[5] = mat[5];
				dest[6] = mat[6];
				dest[7] = mat[7];
				dest[8] = mat[8];
			} else {
				dest[0] = dest[1] =
				dest[2] = dest[3] =
				dest[4] = dest[5] =
				dest[6] = dest[7] =
				dest[8] = 0;
			}

			return dest;
		};

		/**
		 * Creates a new instance of a mat3, initializing it with the given arguments
		 *
		 * @param {number} m00
		 * @param {number} m01
		 * @param {number} m02
		 * @param {number} m10
		 * @param {number} m11
		 * @param {number} m12
		 * @param {number} m20
		 * @param {number} m21
		 * @param {number} m22

		 * @returns {mat3} New mat3
		 */
		mat3.createFrom = function (m00, m01, m02, m10, m11, m12, m20, m21, m22) {
			var dest = new MatrixArray(9);

			dest[0] = m00;
			dest[1] = m01;
			dest[2] = m02;
			dest[3] = m10;
			dest[4] = m11;
			dest[5] = m12;
			dest[6] = m20;
			dest[7] = m21;
			dest[8] = m22;

			return dest;
		};

		/**
		 * Calculates the determinant of a mat3
		 *
		 * @param {mat3} mat mat3 to calculate determinant of
		 *
		 * @returns {Number} determinant of mat
		 */
		mat3.determinant = function (mat) {
			var a00 = mat[0], a01 = mat[1], a02 = mat[2],
				a10 = mat[3], a11 = mat[4], a12 = mat[5],
				a20 = mat[6], a21 = mat[7], a22 = mat[8];

			return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
		};

		/**
		 * Calculates the inverse matrix of a mat3
		 *
		 * @param {mat3} mat mat3 to calculate inverse of
		 * @param {mat3} [dest] mat3 receiving inverse matrix. If not specified result is written to mat
		 *
		 * @param {mat3} dest is specified, mat otherwise, null if matrix cannot be inverted
		 */
		mat3.inverse = function (mat, dest) {
			var a00 = mat[0], a01 = mat[1], a02 = mat[2],
				a10 = mat[3], a11 = mat[4], a12 = mat[5],
				a20 = mat[6], a21 = mat[7], a22 = mat[8],

				b01 = a22 * a11 - a12 * a21,
				b11 = -a22 * a10 + a12 * a20,
				b21 = a21 * a10 - a11 * a20,

				d = a00 * b01 + a01 * b11 + a02 * b21,
				id;

			if (!d) { return null; }
			id = 1 / d;

			if (!dest) { dest = mat3.create(); }

			dest[0] = b01 * id;
			dest[1] = (-a22 * a01 + a02 * a21) * id;
			dest[2] = (a12 * a01 - a02 * a11) * id;
			dest[3] = b11 * id;
			dest[4] = (a22 * a00 - a02 * a20) * id;
			dest[5] = (-a12 * a00 + a02 * a10) * id;
			dest[6] = b21 * id;
			dest[7] = (-a21 * a00 + a01 * a20) * id;
			dest[8] = (a11 * a00 - a01 * a10) * id;
			return dest;
		};
		
		/**
		 * Performs a matrix multiplication
		 *
		 * @param {mat3} mat First operand
		 * @param {mat3} mat2 Second operand
		 * @param {mat3} [dest] mat3 receiving operation result. If not specified result is written to mat
		 *
		 * @returns {mat3} dest if specified, mat otherwise
		 */
		mat3.multiply = function (mat, mat2, dest) {
			if (!dest) { dest = mat; }
			

			// Cache the matrix values (makes for huge speed increases!)
			var a00 = mat[0], a01 = mat[1], a02 = mat[2],
				a10 = mat[3], a11 = mat[4], a12 = mat[5],
				a20 = mat[6], a21 = mat[7], a22 = mat[8],

				b00 = mat2[0], b01 = mat2[1], b02 = mat2[2],
				b10 = mat2[3], b11 = mat2[4], b12 = mat2[5],
				b20 = mat2[6], b21 = mat2[7], b22 = mat2[8];

			dest[0] = b00 * a00 + b01 * a10 + b02 * a20;
			dest[1] = b00 * a01 + b01 * a11 + b02 * a21;
			dest[2] = b00 * a02 + b01 * a12 + b02 * a22;

			dest[3] = b10 * a00 + b11 * a10 + b12 * a20;
			dest[4] = b10 * a01 + b11 * a11 + b12 * a21;
			dest[5] = b10 * a02 + b11 * a12 + b12 * a22;

			dest[6] = b20 * a00 + b21 * a10 + b22 * a20;
			dest[7] = b20 * a01 + b21 * a11 + b22 * a21;
			dest[8] = b20 * a02 + b21 * a12 + b22 * a22;

			return dest;
		};

		/**
		 * Transforms the vec2 according to the given mat3.
		 *
		 * @param {mat3} matrix mat3 to multiply against
		 * @param {vec2} vec    the vector to multiply
		 * @param {vec2} [dest] an optional receiving vector. If not given, vec is used.
		 *
		 * @returns {vec2} The multiplication result
		 **/
		mat3.multiplyVec2 = function(matrix, vec, dest) {
		  if (!dest) dest = vec;
		  var x = vec[0], y = vec[1];
		  dest[0] = x * matrix[0] + y * matrix[3] + matrix[6];
		  dest[1] = x * matrix[1] + y * matrix[4] + matrix[7];
		  return dest;
		};

		/**
		 * Transforms the vec3 according to the given mat3
		 *
		 * @param {mat3} matrix mat3 to multiply against
		 * @param {vec3} vec    the vector to multiply
		 * @param {vec3} [dest] an optional receiving vector. If not given, vec is used.
		 *
		 * @returns {vec3} The multiplication result
		 **/
		mat3.multiplyVec3 = function(matrix, vec, dest) {
		  if (!dest) dest = vec;
		  var x = vec[0], y = vec[1], z = vec[2];
		  dest[0] = x * matrix[0] + y * matrix[3] + z * matrix[6];
		  dest[1] = x * matrix[1] + y * matrix[4] + z * matrix[7];
		  dest[2] = x * matrix[2] + y * matrix[5] + z * matrix[8];
		  
		  return dest;
		};

		/**
		 * Copies the values of one mat3 to another
		 *
		 * @param {mat3} mat mat3 containing values to copy
		 * @param {mat3} dest mat3 receiving copied values
		 *
		 * @returns {mat3} dest
		 */
		mat3.set = function (mat, dest) {
			dest[0] = mat[0];
			dest[1] = mat[1];
			dest[2] = mat[2];
			dest[3] = mat[3];
			dest[4] = mat[4];
			dest[5] = mat[5];
			dest[6] = mat[6];
			dest[7] = mat[7];
			dest[8] = mat[8];
			return dest;
		};

		/**
		 * Sets a mat3 to an identity matrix
		 *
		 * @param {mat3} dest mat3 to set
		 *
		 * @returns dest if specified, otherwise a new mat3
		 */
		mat3.identity = function (dest) {
			if (!dest) { dest = mat3.create(); }
			dest[0] = 1;
			dest[1] = 0;
			dest[2] = 0;
			dest[3] = 0;
			dest[4] = 1;
			dest[5] = 0;
			dest[6] = 0;
			dest[7] = 0;
			dest[8] = 1;
			return dest;
		};

		/**
		 * Transposes a mat3 (flips the values over the diagonal)
		 *
		 * Params:
		 * @param {mat3} mat mat3 to transpose
		 * @param {mat3} [dest] mat3 receiving transposed values. If not specified result is written to mat
		 *
		 * @returns {mat3} dest is specified, mat otherwise
		 */
		mat3.transpose = function (mat, dest) {
			// If we are transposing ourselves we can skip a few steps but have to cache some values
			if (!dest || mat === dest) {
				var a01 = mat[1], a02 = mat[2],
					a12 = mat[5];

				mat[1] = mat[3];
				mat[2] = mat[6];
				mat[3] = a01;
				mat[5] = mat[7];
				mat[6] = a02;
				mat[7] = a12;
				return mat;
			}

			dest[0] = mat[0];
			dest[1] = mat[3];
			dest[2] = mat[6];
			dest[3] = mat[1];
			dest[4] = mat[4];
			dest[5] = mat[7];
			dest[6] = mat[2];
			dest[7] = mat[5];
			dest[8] = mat[8];
			return dest;
		};

		/**
		 * Copies the elements of a mat3 into the upper 3x3 elements of a mat4
		 *
		 * @param {mat3} mat mat3 containing values to copy
		 * @param {mat4} [dest] mat4 receiving copied values
		 *
		 * @returns {mat4} dest if specified, a new mat4 otherwise
		 */
		mat3.toMat4 = function (mat, dest) {
			if (!dest) { dest = mat4.create(); }

			dest[15] = 1;
			dest[14] = 0;
			dest[13] = 0;
			dest[12] = 0;

			dest[11] = 0;
			dest[10] = mat[8];
			dest[9] = mat[7];
			dest[8] = mat[6];

			dest[7] = 0;
			dest[6] = mat[5];
			dest[5] = mat[4];
			dest[4] = mat[3];

			dest[3] = 0;
			dest[2] = mat[2];
			dest[1] = mat[1];
			dest[0] = mat[0];

			return dest;
		};

		/**
		 * Returns a string representation of a mat3
		 *
		 * @param {mat3} mat mat3 to represent as a string
		 *
		 * @param {string} String representation of mat
		 */
		mat3.str = function (mat) {
			return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] +
				', ' + mat[3] + ', ' + mat[4] + ', ' + mat[5] +
				', ' + mat[6] + ', ' + mat[7] + ', ' + mat[8] + ']';
		};

		/**
		 * @class 4x4 Matrix
		 * @name mat4
		 */
		var mat4 = {};

		/**
		 * Creates a new instance of a mat4 using the default array type
		 * Any javascript array-like object containing at least 16 numeric elements can serve as a mat4
		 *
		 * @param {mat4} [mat] mat4 containing values to initialize with
		 *
		 * @returns {mat4} New mat4
		 */
		mat4.create = function (mat) {
			var dest = new MatrixArray(16);

			if(arguments.length === 4) {
				dest[0] = arguments[0];
				dest[1] = arguments[1];
				dest[2] = arguments[2];
				dest[3] = arguments[3];
				dest[4] = arguments[4];
				dest[5] = arguments[5];
				dest[6] = arguments[6];
				dest[7] = arguments[7];
				dest[8] = arguments[8];
				dest[9] = arguments[9];
				dest[10] = arguments[10];
				dest[11] = arguments[11];
				dest[12] = arguments[12];
				dest[13] = arguments[13];
				dest[14] = arguments[14];
				dest[15] = arguments[15];
			} else if (mat) {
				dest[0] = mat[0];
				dest[1] = mat[1];
				dest[2] = mat[2];
				dest[3] = mat[3];
				dest[4] = mat[4];
				dest[5] = mat[5];
				dest[6] = mat[6];
				dest[7] = mat[7];
				dest[8] = mat[8];
				dest[9] = mat[9];
				dest[10] = mat[10];
				dest[11] = mat[11];
				dest[12] = mat[12];
				dest[13] = mat[13];
				dest[14] = mat[14];
				dest[15] = mat[15];
			}

			return dest;
		};

		/**
		 * Creates a new instance of a mat4, initializing it with the given arguments
		 *
		 * @param {number} m00
		 * @param {number} m01
		 * @param {number} m02
		 * @param {number} m03
		 * @param {number} m10
		 * @param {number} m11
		 * @param {number} m12
		 * @param {number} m13
		 * @param {number} m20
		 * @param {number} m21
		 * @param {number} m22
		 * @param {number} m23
		 * @param {number} m30
		 * @param {number} m31
		 * @param {number} m32
		 * @param {number} m33

		 * @returns {mat4} New mat4
		 */
		mat4.createFrom = function (m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
			var dest = new MatrixArray(16);

			dest[0] = m00;
			dest[1] = m01;
			dest[2] = m02;
			dest[3] = m03;
			dest[4] = m10;
			dest[5] = m11;
			dest[6] = m12;
			dest[7] = m13;
			dest[8] = m20;
			dest[9] = m21;
			dest[10] = m22;
			dest[11] = m23;
			dest[12] = m30;
			dest[13] = m31;
			dest[14] = m32;
			dest[15] = m33;

			return dest;
		};

		/**
		 * Copies the values of one mat4 to another
		 *
		 * @param {mat4} mat mat4 containing values to copy
		 * @param {mat4} dest mat4 receiving copied values
		 *
		 * @returns {mat4} dest
		 */
		mat4.set = function (mat, dest) {
			dest[0] = mat[0];
			dest[1] = mat[1];
			dest[2] = mat[2];
			dest[3] = mat[3];
			dest[4] = mat[4];
			dest[5] = mat[5];
			dest[6] = mat[6];
			dest[7] = mat[7];
			dest[8] = mat[8];
			dest[9] = mat[9];
			dest[10] = mat[10];
			dest[11] = mat[11];
			dest[12] = mat[12];
			dest[13] = mat[13];
			dest[14] = mat[14];
			dest[15] = mat[15];
			return dest;
		};

		/**
		 * Sets a mat4 to an identity matrix
		 *
		 * @param {mat4} dest mat4 to set
		 *
		 * @returns {mat4} dest
		 */
		mat4.identity = function (dest) {
			if (!dest) { dest = mat4.create(); }
			dest[0] = 1;
			dest[1] = 0;
			dest[2] = 0;
			dest[3] = 0;
			dest[4] = 0;
			dest[5] = 1;
			dest[6] = 0;
			dest[7] = 0;
			dest[8] = 0;
			dest[9] = 0;
			dest[10] = 1;
			dest[11] = 0;
			dest[12] = 0;
			dest[13] = 0;
			dest[14] = 0;
			dest[15] = 1;
			return dest;
		};

		/**
		 * Transposes a mat4 (flips the values over the diagonal)
		 *
		 * @param {mat4} mat mat4 to transpose
		 * @param {mat4} [dest] mat4 receiving transposed values. If not specified result is written to mat
		 *
		 * @param {mat4} dest is specified, mat otherwise
		 */
		mat4.transpose = function (mat, dest) {
			// If we are transposing ourselves we can skip a few steps but have to cache some values
			if (!dest || mat === dest) {
				var a01 = mat[1], a02 = mat[2], a03 = mat[3],
					a12 = mat[6], a13 = mat[7],
					a23 = mat[11];

				mat[1] = mat[4];
				mat[2] = mat[8];
				mat[3] = mat[12];
				mat[4] = a01;
				mat[6] = mat[9];
				mat[7] = mat[13];
				mat[8] = a02;
				mat[9] = a12;
				mat[11] = mat[14];
				mat[12] = a03;
				mat[13] = a13;
				mat[14] = a23;
				return mat;
			}

			dest[0] = mat[0];
			dest[1] = mat[4];
			dest[2] = mat[8];
			dest[3] = mat[12];
			dest[4] = mat[1];
			dest[5] = mat[5];
			dest[6] = mat[9];
			dest[7] = mat[13];
			dest[8] = mat[2];
			dest[9] = mat[6];
			dest[10] = mat[10];
			dest[11] = mat[14];
			dest[12] = mat[3];
			dest[13] = mat[7];
			dest[14] = mat[11];
			dest[15] = mat[15];
			return dest;
		};

		/**
		 * Calculates the determinant of a mat4
		 *
		 * @param {mat4} mat mat4 to calculate determinant of
		 *
		 * @returns {number} determinant of mat
		 */
		mat4.determinant = function (mat) {
			// Cache the matrix values (makes for huge speed increases!)
			var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3],
				a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7],
				a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11],
				a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];

			return (a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 +
					a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 +
					a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 +
					a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 +
					a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 +
					a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33);
		};

		/**
		 * Calculates the inverse matrix of a mat4
		 *
		 * @param {mat4} mat mat4 to calculate inverse of
		 * @param {mat4} [dest] mat4 receiving inverse matrix. If not specified result is written to mat
		 *
		 * @param {mat4} dest is specified, mat otherwise, null if matrix cannot be inverted
		 */
		mat4.inverse = function (mat, dest) {
			if (!dest) { dest = mat; }

			// Cache the matrix values (makes for huge speed increases!)
			var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3],
				a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7],
				a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11],
				a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15],

				b00 = a00 * a11 - a01 * a10,
				b01 = a00 * a12 - a02 * a10,
				b02 = a00 * a13 - a03 * a10,
				b03 = a01 * a12 - a02 * a11,
				b04 = a01 * a13 - a03 * a11,
				b05 = a02 * a13 - a03 * a12,
				b06 = a20 * a31 - a21 * a30,
				b07 = a20 * a32 - a22 * a30,
				b08 = a20 * a33 - a23 * a30,
				b09 = a21 * a32 - a22 * a31,
				b10 = a21 * a33 - a23 * a31,
				b11 = a22 * a33 - a23 * a32,

				d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06),
				invDet;

				// Calculate the determinant
				if (!d) { return null; }
				invDet = 1 / d;

			dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet;
			dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet;
			dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet;
			dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet;
			dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet;
			dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet;
			dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet;
			dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet;
			dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet;
			dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet;
			dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet;
			dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet;
			dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet;
			dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet;
			dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet;
			dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet;

			return dest;
		};

		/**
		 * Copies the upper 3x3 elements of a mat4 into another mat4
		 *
		 * @param {mat4} mat mat4 containing values to copy
		 * @param {mat4} [dest] mat4 receiving copied values
		 *
		 * @returns {mat4} dest is specified, a new mat4 otherwise
		 */
		mat4.toRotationMat = function (mat, dest) {
			if (!dest) { dest = mat4.create(); }

			dest[0] = mat[0];
			dest[1] = mat[1];
			dest[2] = mat[2];
			dest[3] = mat[3];
			dest[4] = mat[4];
			dest[5] = mat[5];
			dest[6] = mat[6];
			dest[7] = mat[7];
			dest[8] = mat[8];
			dest[9] = mat[9];
			dest[10] = mat[10];
			dest[11] = mat[11];
			dest[12] = 0;
			dest[13] = 0;
			dest[14] = 0;
			dest[15] = 1;

			return dest;
		};

		/**
		 * Copies the upper 3x3 elements of a mat4 into a mat3
		 *
		 * @param {mat4} mat mat4 containing values to copy
		 * @param {mat3} [dest] mat3 receiving copied values
		 *
		 * @returns {mat3} dest is specified, a new mat3 otherwise
		 */
		mat4.toMat3 = function (mat, dest) {
			if (!dest) { dest = mat3.create(); }

			dest[0] = mat[0];
			dest[1] = mat[1];
			dest[2] = mat[2];
			dest[3] = mat[4];
			dest[4] = mat[5];
			dest[5] = mat[6];
			dest[6] = mat[8];
			dest[7] = mat[9];
			dest[8] = mat[10];

			return dest;
		};

		/**
		 * Calculates the inverse of the upper 3x3 elements of a mat4 and copies the result into a mat3
		 * The resulting matrix is useful for calculating transformed normals
		 *
		 * Params:
		 * @param {mat4} mat mat4 containing values to invert and copy
		 * @param {mat3} [dest] mat3 receiving values
		 *
		 * @returns {mat3} dest is specified, a new mat3 otherwise, null if the matrix cannot be inverted
		 */
		mat4.toInverseMat3 = function (mat, dest) {
			// Cache the matrix values (makes for huge speed increases!)
			var a00 = mat[0], a01 = mat[1], a02 = mat[2],
				a10 = mat[4], a11 = mat[5], a12 = mat[6],
				a20 = mat[8], a21 = mat[9], a22 = mat[10],

				b01 = a22 * a11 - a12 * a21,
				b11 = -a22 * a10 + a12 * a20,
				b21 = a21 * a10 - a11 * a20,

				d = a00 * b01 + a01 * b11 + a02 * b21,
				id;

			if (!d) { return null; }
			id = 1 / d;

			if (!dest) { dest = mat3.create(); }

			dest[0] = b01 * id;
			dest[1] = (-a22 * a01 + a02 * a21) * id;
			dest[2] = (a12 * a01 - a02 * a11) * id;
			dest[3] = b11 * id;
			dest[4] = (a22 * a00 - a02 * a20) * id;
			dest[5] = (-a12 * a00 + a02 * a10) * id;
			dest[6] = b21 * id;
			dest[7] = (-a21 * a00 + a01 * a20) * id;
			dest[8] = (a11 * a00 - a01 * a10) * id;

			return dest;
		};

		/**
		 * Performs a matrix multiplication
		 *
		 * @param {mat4} mat First operand
		 * @param {mat4} mat2 Second operand
		 * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat
		 *
		 * @returns {mat4} dest if specified, mat otherwise
		 */
		mat4.multiply = function (mat, mat2, dest) {
			if (!dest) { dest = mat; }

			// Cache the matrix values (makes for huge speed increases!)
			var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3];
			var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7];
			var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11];
			var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];

			// Cache only the current line of the second matrix
			var b0  = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3];  
			dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
			dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
			dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
			dest[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;

			b0 = mat2[4];
			b1 = mat2[5];
			b2 = mat2[6];
			b3 = mat2[7];
			dest[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
			dest[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
			dest[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
			dest[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;

			b0 = mat2[8];
			b1 = mat2[9];
			b2 = mat2[10];
			b3 = mat2[11];
			dest[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
			dest[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
			dest[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
			dest[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;

			b0 = mat2[12];
			b1 = mat2[13];
			b2 = mat2[14];
			b3 = mat2[15];
			dest[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
			dest[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
			dest[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
			dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;

			return dest;
		};

		/**
		 * Transforms a vec3 with the given matrix
		 * 4th vector component is implicitly '1'
		 *
		 * @param {mat4} mat mat4 to transform the vector with
		 * @param {vec3} vec vec3 to transform
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec3} dest if specified, vec otherwise
		 */
		mat4.multiplyVec3 = function (mat, vec, dest) {
			if (!dest) { dest = vec; }

			var x = vec[0], y = vec[1], z = vec[2];

			dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12];
			dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13];
			dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14];

			return dest;
		};

		/**
		 * Transforms a vec4 with the given matrix
		 *
		 * @param {mat4} mat mat4 to transform the vector with
		 * @param {vec4} vec vec4 to transform
		 * @param {vec4} [dest] vec4 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec4} dest if specified, vec otherwise
		 */
		mat4.multiplyVec4 = function (mat, vec, dest) {
			if (!dest) { dest = vec; }

			var x = vec[0], y = vec[1], z = vec[2], w = vec[3];

			dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12] * w;
			dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13] * w;
			dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14] * w;
			dest[3] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15] * w;

			return dest;
		};

		/**
		 * Translates a matrix by the given vector
		 *
		 * @param {mat4} mat mat4 to translate
		 * @param {vec3} vec vec3 specifying the translation
		 * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat
		 *
		 * @returns {mat4} dest if specified, mat otherwise
		 */
		mat4.translate = function (mat, vec, dest) {
			var x = vec[0], y = vec[1], z = vec[2],
				a00, a01, a02, a03,
				a10, a11, a12, a13,
				a20, a21, a22, a23;

			if (!dest || mat === dest) {
				mat[12] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12];
				mat[13] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13];
				mat[14] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14];
				mat[15] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15];
				return mat;
			}

			a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3];
			a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7];
			a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11];

			dest[0] = a00; dest[1] = a01; dest[2] = a02; dest[3] = a03;
			dest[4] = a10; dest[5] = a11; dest[6] = a12; dest[7] = a13;
			dest[8] = a20; dest[9] = a21; dest[10] = a22; dest[11] = a23;

			dest[12] = a00 * x + a10 * y + a20 * z + mat[12];
			dest[13] = a01 * x + a11 * y + a21 * z + mat[13];
			dest[14] = a02 * x + a12 * y + a22 * z + mat[14];
			dest[15] = a03 * x + a13 * y + a23 * z + mat[15];
			return dest;
		};

		/**
		 * Scales a matrix by the given vector
		 *
		 * @param {mat4} mat mat4 to scale
		 * @param {vec3} vec vec3 specifying the scale for each axis
		 * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat
		 *
		 * @param {mat4} dest if specified, mat otherwise
		 */
		mat4.scale = function (mat, vec, dest) {
			var x = vec[0], y = vec[1], z = vec[2];

			if (!dest || mat === dest) {
				mat[0] *= x;
				mat[1] *= x;
				mat[2] *= x;
				mat[3] *= x;
				mat[4] *= y;
				mat[5] *= y;
				mat[6] *= y;
				mat[7] *= y;
				mat[8] *= z;
				mat[9] *= z;
				mat[10] *= z;
				mat[11] *= z;
				return mat;
			}

			dest[0] = mat[0] * x;
			dest[1] = mat[1] * x;
			dest[2] = mat[2] * x;
			dest[3] = mat[3] * x;
			dest[4] = mat[4] * y;
			dest[5] = mat[5] * y;
			dest[6] = mat[6] * y;
			dest[7] = mat[7] * y;
			dest[8] = mat[8] * z;
			dest[9] = mat[9] * z;
			dest[10] = mat[10] * z;
			dest[11] = mat[11] * z;
			dest[12] = mat[12];
			dest[13] = mat[13];
			dest[14] = mat[14];
			dest[15] = mat[15];
			return dest;
		};

		/**
		 * Rotates a matrix by the given angle around the specified axis
		 * If rotating around a primary axis (X,Y,Z) one of the specialized rotation functions should be used instead for performance
		 *
		 * @param {mat4} mat mat4 to rotate
		 * @param {number} angle Angle (in radians) to rotate
		 * @param {vec3} axis vec3 representing the axis to rotate around
		 * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat
		 *
		 * @returns {mat4} dest if specified, mat otherwise
		 */
		mat4.rotate = function (mat, angle, axis, dest) {
			var x = axis[0], y = axis[1], z = axis[2],
				len = Math.sqrt(x * x + y * y + z * z),
				s, c, t,
				a00, a01, a02, a03,
				a10, a11, a12, a13,
				a20, a21, a22, a23,
				b00, b01, b02,
				b10, b11, b12,
				b20, b21, b22;

			if (!len) { return null; }
			if (len !== 1) {
				len = 1 / len;
				x *= len;
				y *= len;
				z *= len;
			}

			s = Math.sin(angle);
			c = Math.cos(angle);
			t = 1 - c;

			a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3];
			a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7];
			a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11];

			// Construct the elements of the rotation matrix
			b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
			b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
			b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;

			if (!dest) {
				dest = mat;
			} else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row
				dest[12] = mat[12];
				dest[13] = mat[13];
				dest[14] = mat[14];
				dest[15] = mat[15];
			}

			// Perform rotation-specific matrix multiplication
			dest[0] = a00 * b00 + a10 * b01 + a20 * b02;
			dest[1] = a01 * b00 + a11 * b01 + a21 * b02;
			dest[2] = a02 * b00 + a12 * b01 + a22 * b02;
			dest[3] = a03 * b00 + a13 * b01 + a23 * b02;

			dest[4] = a00 * b10 + a10 * b11 + a20 * b12;
			dest[5] = a01 * b10 + a11 * b11 + a21 * b12;
			dest[6] = a02 * b10 + a12 * b11 + a22 * b12;
			dest[7] = a03 * b10 + a13 * b11 + a23 * b12;

			dest[8] = a00 * b20 + a10 * b21 + a20 * b22;
			dest[9] = a01 * b20 + a11 * b21 + a21 * b22;
			dest[10] = a02 * b20 + a12 * b21 + a22 * b22;
			dest[11] = a03 * b20 + a13 * b21 + a23 * b22;
			return dest;
		};

		/**
		 * Rotates a matrix by the given angle around the X axis
		 *
		 * @param {mat4} mat mat4 to rotate
		 * @param {number} angle Angle (in radians) to rotate
		 * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat
		 *
		 * @returns {mat4} dest if specified, mat otherwise
		 */
		mat4.rotateX = function (mat, angle, dest) {
			var s = Math.sin(angle),
				c = Math.cos(angle),
				a10 = mat[4],
				a11 = mat[5],
				a12 = mat[6],
				a13 = mat[7],
				a20 = mat[8],
				a21 = mat[9],
				a22 = mat[10],
				a23 = mat[11];

			if (!dest) {
				dest = mat;
			} else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows
				dest[0] = mat[0];
				dest[1] = mat[1];
				dest[2] = mat[2];
				dest[3] = mat[3];

				dest[12] = mat[12];
				dest[13] = mat[13];
				dest[14] = mat[14];
				dest[15] = mat[15];
			}

			// Perform axis-specific matrix multiplication
			dest[4] = a10 * c + a20 * s;
			dest[5] = a11 * c + a21 * s;
			dest[6] = a12 * c + a22 * s;
			dest[7] = a13 * c + a23 * s;

			dest[8] = a10 * -s + a20 * c;
			dest[9] = a11 * -s + a21 * c;
			dest[10] = a12 * -s + a22 * c;
			dest[11] = a13 * -s + a23 * c;
			return dest;
		};

		/**
		 * Rotates a matrix by the given angle around the Y axis
		 *
		 * @param {mat4} mat mat4 to rotate
		 * @param {number} angle Angle (in radians) to rotate
		 * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat
		 *
		 * @returns {mat4} dest if specified, mat otherwise
		 */
		mat4.rotateY = function (mat, angle, dest) {
			var s = Math.sin(angle),
				c = Math.cos(angle),
				a00 = mat[0],
				a01 = mat[1],
				a02 = mat[2],
				a03 = mat[3],
				a20 = mat[8],
				a21 = mat[9],
				a22 = mat[10],
				a23 = mat[11];

			if (!dest) {
				dest = mat;
			} else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows
				dest[4] = mat[4];
				dest[5] = mat[5];
				dest[6] = mat[6];
				dest[7] = mat[7];

				dest[12] = mat[12];
				dest[13] = mat[13];
				dest[14] = mat[14];
				dest[15] = mat[15];
			}

			// Perform axis-specific matrix multiplication
			dest[0] = a00 * c + a20 * -s;
			dest[1] = a01 * c + a21 * -s;
			dest[2] = a02 * c + a22 * -s;
			dest[3] = a03 * c + a23 * -s;

			dest[8] = a00 * s + a20 * c;
			dest[9] = a01 * s + a21 * c;
			dest[10] = a02 * s + a22 * c;
			dest[11] = a03 * s + a23 * c;
			return dest;
		};

		/**
		 * Rotates a matrix by the given angle around the Z axis
		 *
		 * @param {mat4} mat mat4 to rotate
		 * @param {number} angle Angle (in radians) to rotate
		 * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat
		 *
		 * @returns {mat4} dest if specified, mat otherwise
		 */
		mat4.rotateZ = function (mat, angle, dest) {
			var s = Math.sin(angle),
				c = Math.cos(angle),
				a00 = mat[0],
				a01 = mat[1],
				a02 = mat[2],
				a03 = mat[3],
				a10 = mat[4],
				a11 = mat[5],
				a12 = mat[6],
				a13 = mat[7];

			if (!dest) {
				dest = mat;
			} else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row
				dest[8] = mat[8];
				dest[9] = mat[9];
				dest[10] = mat[10];
				dest[11] = mat[11];

				dest[12] = mat[12];
				dest[13] = mat[13];
				dest[14] = mat[14];
				dest[15] = mat[15];
			}

			// Perform axis-specific matrix multiplication
			dest[0] = a00 * c + a10 * s;
			dest[1] = a01 * c + a11 * s;
			dest[2] = a02 * c + a12 * s;
			dest[3] = a03 * c + a13 * s;

			dest[4] = a00 * -s + a10 * c;
			dest[5] = a01 * -s + a11 * c;
			dest[6] = a02 * -s + a12 * c;
			dest[7] = a03 * -s + a13 * c;

			return dest;
		};

		/**
		 * Generates a frustum matrix with the given bounds
		 *
		 * @param {number} left Left bound of the frustum
		 * @param {number} right Right bound of the frustum
		 * @param {number} bottom Bottom bound of the frustum
		 * @param {number} top Top bound of the frustum
		 * @param {number} near Near bound of the frustum
		 * @param {number} far Far bound of the frustum
		 * @param {mat4} [dest] mat4 frustum matrix will be written into
		 *
		 * @returns {mat4} dest if specified, a new mat4 otherwise
		 */
		mat4.frustum = function (left, right, bottom, top, near, far, dest) {
			if (!dest) { dest = mat4.create(); }
			var rl = (right - left),
				tb = (top - bottom),
				fn = (far - near);
			dest[0] = (near * 2) / rl;
			dest[1] = 0;
			dest[2] = 0;
			dest[3] = 0;
			dest[4] = 0;
			dest[5] = (near * 2) / tb;
			dest[6] = 0;
			dest[7] = 0;
			dest[8] = (right + left) / rl;
			dest[9] = (top + bottom) / tb;
			dest[10] = -(far + near) / fn;
			dest[11] = -1;
			dest[12] = 0;
			dest[13] = 0;
			dest[14] = -(far * near * 2) / fn;
			dest[15] = 0;
			return dest;
		};

		/**
		 * Generates a perspective projection matrix with the given bounds
		 *
		 * @param {number} fovy Vertical field of view
		 * @param {number} aspect Aspect ratio. typically viewport width/height
		 * @param {number} near Near bound of the frustum
		 * @param {number} far Far bound of the frustum
		 * @param {mat4} [dest] mat4 frustum matrix will be written into
		 *
		 * @returns {mat4} dest if specified, a new mat4 otherwise
		 */
		Math.tan = function( n )
		{
			return Math.sin( n ) / Math.cos( n );
		};
		mat4.perspective = function (fovy, aspect, near, far, dest) {
			var top = near * Math.tan(fovy * Math.PI / 360.0),
				right = top * aspect;
			return mat4.frustum(-right, right, -top, top, near, far, dest);
		};

		/**
		 * Generates a orthogonal projection matrix with the given bounds
		 *
		 * @param {number} left Left bound of the frustum
		 * @param {number} right Right bound of the frustum
		 * @param {number} bottom Bottom bound of the frustum
		 * @param {number} top Top bound of the frustum
		 * @param {number} near Near bound of the frustum
		 * @param {number} far Far bound of the frustum
		 * @param {mat4} [dest] mat4 frustum matrix will be written into
		 *
		 * @returns {mat4} dest if specified, a new mat4 otherwise
		 */
		mat4.ortho = function (left, right, bottom, top, near, far, dest) {
			if (!dest) { dest = mat4.create(); }
			var rl = (right - left),
				tb = (top - bottom),
				fn = (far - near);
			dest[0] = 2 / rl;
			dest[1] = 0;
			dest[2] = 0;
			dest[3] = 0;
			dest[4] = 0;
			dest[5] = 2 / tb;
			dest[6] = 0;
			dest[7] = 0;
			dest[8] = 0;
			dest[9] = 0;
			dest[10] = -2 / fn;
			dest[11] = 0;
			dest[12] = -(left + right) / rl;
			dest[13] = -(top + bottom) / tb;
			dest[14] = -(far + near) / fn;
			dest[15] = 1;
			return dest;
		};

		/**
		 * Generates a look-at matrix with the given eye position, focal point, and up axis
		 *
		 * @param {vec3} eye Position of the viewer
		 * @param {vec3} center Point the viewer is looking at
		 * @param {vec3} up vec3 pointing "up"
		 * @param {mat4} [dest] mat4 frustum matrix will be written into
		 *
		 * @returns {mat4} dest if specified, a new mat4 otherwise
		 */
		mat4.lookAt = function (eye, center, up, dest) {
			if (!dest) { dest = mat4.create(); }

			var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
				eyex = eye[0],
				eyey = eye[1],
				eyez = eye[2],
				upx = up[0],
				upy = up[1],
				upz = up[2],
				centerx = center[0],
				centery = center[1],
				centerz = center[2];

			if (eyex === centerx && eyey === centery && eyez === centerz) {
				return mat4.identity(dest);
			}

			//vec3.direction(eye, center, z);
			z0 = eyex - centerx;
			z1 = eyey - centery;
			z2 = eyez - centerz;

			// normalize (no check needed for 0 because of early return)
			len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
			z0 *= len;
			z1 *= len;
			z2 *= len;

			//vec3.normalize(vec3.cross(up, z, x));
			x0 = upy * z2 - upz * z1;
			x1 = upz * z0 - upx * z2;
			x2 = upx * z1 - upy * z0;
			len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
			if (!len) {
				x0 = 0;
				x1 = 0;
				x2 = 0;
			} else {
				len = 1 / len;
				x0 *= len;
				x1 *= len;
				x2 *= len;
			}

			//vec3.normalize(vec3.cross(z, x, y));
			y0 = z1 * x2 - z2 * x1;
			y1 = z2 * x0 - z0 * x2;
			y2 = z0 * x1 - z1 * x0;

			len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
			if (!len) {
				y0 = 0;
				y1 = 0;
				y2 = 0;
			} else {
				len = 1 / len;
				y0 *= len;
				y1 *= len;
				y2 *= len;
			}

			dest[0] = x0;
			dest[1] = y0;
			dest[2] = z0;
			dest[3] = 0;
			dest[4] = x1;
			dest[5] = y1;
			dest[6] = z1;
			dest[7] = 0;
			dest[8] = x2;
			dest[9] = y2;
			dest[10] = z2;
			dest[11] = 0;
			dest[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
			dest[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
			dest[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
			dest[15] = 1;

			return dest;
		};

		/**
		 * Creates a matrix from a quaternion rotation and vector translation
		 * This is equivalent to (but much faster than):
		 *
		 *     mat4.identity(dest);
		 *     mat4.translate(dest, vec);
		 *     var quatMat = mat4.create();
		 *     quat4.toMat4(quat, quatMat);
		 *     mat4.multiply(dest, quatMat);
		 *
		 * @param {quat4} quat Rotation quaternion
		 * @param {vec3} vec Translation vector
		 * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to a new mat4
		 *
		 * @returns {mat4} dest if specified, a new mat4 otherwise
		 */
		mat4.fromRotationTranslation = function (quat, vec, dest) {
			if (!dest) { dest = mat4.create(); }

			// Quaternion math
			var x = quat[0], y = quat[1], z = quat[2], w = quat[3],
				x2 = x + x,
				y2 = y + y,
				z2 = z + z,

				xx = x * x2,
				xy = x * y2,
				xz = x * z2,
				yy = y * y2,
				yz = y * z2,
				zz = z * z2,
				wx = w * x2,
				wy = w * y2,
				wz = w * z2;

			dest[0] = 1 - (yy + zz);
			dest[1] = xy + wz;
			dest[2] = xz - wy;
			dest[3] = 0;
			dest[4] = xy - wz;
			dest[5] = 1 - (xx + zz);
			dest[6] = yz + wx;
			dest[7] = 0;
			dest[8] = xz + wy;
			dest[9] = yz - wx;
			dest[10] = 1 - (xx + yy);
			dest[11] = 0;
			dest[12] = vec[0];
			dest[13] = vec[1];
			dest[14] = vec[2];
			dest[15] = 1;
			
			return dest;
		};

		/**
		 * Returns a string representation of a mat4
		 *
		 * @param {mat4} mat mat4 to represent as a string
		 *
		 * @returns {string} String representation of mat
		 */
		mat4.str = function (mat) {
			return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + ', ' + mat[3] +
				', ' + mat[4] + ', ' + mat[5] + ', ' + mat[6] + ', ' + mat[7] +
				', ' + mat[8] + ', ' + mat[9] + ', ' + mat[10] + ', ' + mat[11] +
				', ' + mat[12] + ', ' + mat[13] + ', ' + mat[14] + ', ' + mat[15] + ']';
		};

		/**
		 * @class Quaternion
		 * @name quat4
		 */
		var quat4 = {};

		/**
		 * Creates a new instance of a quat4 using the default array type
		 * Any javascript array containing at least 4 numeric elements can serve as a quat4
		 *
		 * @param {quat4} [quat] quat4 containing values to initialize with
		 *
		 * @returns {quat4} New quat4
		 */
		quat4.create = function (quat) {
			var dest = new MatrixArray(4);

			if (quat) {
				dest[0] = quat[0];
				dest[1] = quat[1];
				dest[2] = quat[2];
				dest[3] = quat[3];
			} else {
				dest[0] = dest[1] = dest[2] = dest[3] = 0;
			}

			return dest;
		};

		/**
		 * Creates a new instance of a quat4, initializing it with the given arguments
		 *
		 * @param {number} x X value
		 * @param {number} y Y value
		 * @param {number} z Z value
		 * @param {number} w W value

		 * @returns {quat4} New quat4
		 */
		quat4.createFrom = function (x, y, z, w) {
			var dest = new MatrixArray(4);

			dest[0] = x;
			dest[1] = y;
			dest[2] = z;
			dest[3] = w;

			return dest;
		};

		/**
		 * Copies the values of one quat4 to another
		 *
		 * @param {quat4} quat quat4 containing values to copy
		 * @param {quat4} dest quat4 receiving copied values
		 *
		 * @returns {quat4} dest
		 */
		quat4.set = function (quat, dest) {
			dest[0] = quat[0];
			dest[1] = quat[1];
			dest[2] = quat[2];
			dest[3] = quat[3];

			return dest;
		};

		/**
		 * Creates a new identity Quat4
		 *
		 * @param {quat4} [dest] quat4 receiving copied values
		 *
		 * @returns {quat4} dest is specified, new quat4 otherwise
		 */
		quat4.identity = function (dest) {
			if (!dest) { dest = quat4.create(); }
			dest[0] = 0;
			dest[1] = 0;
			dest[2] = 0;
			dest[3] = 1;
			return dest;
		};

		var identityQuat4 = quat4.identity();

		/**
		 * Calculates the W component of a quat4 from the X, Y, and Z components.
		 * Assumes that quaternion is 1 unit in length.
		 * Any existing W component will be ignored.
		 *
		 * @param {quat4} quat quat4 to calculate W component of
		 * @param {quat4} [dest] quat4 receiving calculated values. If not specified result is written to quat
		 *
		 * @returns {quat4} dest if specified, quat otherwise
		 */
		quat4.calculateW = function (quat, dest) {
			var x = quat[0], y = quat[1], z = quat[2];

			if (!dest || quat === dest) {
				quat[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
				return quat;
			}
			dest[0] = x;
			dest[1] = y;
			dest[2] = z;
			dest[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
			return dest;
		};

		/**
		 * Calculates the dot product of two quaternions
		 *
		 * @param {quat4} quat First operand
		 * @param {quat4} quat2 Second operand
		 *
		 * @return {number} Dot product of quat and quat2
		 */
		quat4.dot = function(quat, quat2){
			return quat[0]*quat2[0] + quat[1]*quat2[1] + quat[2]*quat2[2] + quat[3]*quat2[3];
		};

		/**
		 * Calculates the inverse of a quat4
		 *
		 * @param {quat4} quat quat4 to calculate inverse of
		 * @param {quat4} [dest] quat4 receiving inverse values. If not specified result is written to quat
		 *
		 * @returns {quat4} dest if specified, quat otherwise
		 */
		quat4.inverse = function(quat, dest) {
			var q0 = quat[0], q1 = quat[1], q2 = quat[2], q3 = quat[3],
				dot = q0*q0 + q1*q1 + q2*q2 + q3*q3,
				invDot = dot ? 1.0/dot : 0;
			
			// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
			
			if(!dest || quat === dest) {
				quat[0] *= -invDot;
				quat[1] *= -invDot;
				quat[2] *= -invDot;
				quat[3] *= invDot;
				return quat;
			}
			dest[0] = -quat[0]*invDot;
			dest[1] = -quat[1]*invDot;
			dest[2] = -quat[2]*invDot;
			dest[3] = quat[3]*invDot;
			return dest;
		};


		/**
		 * Calculates the conjugate of a quat4
		 * If the quaternion is normalized, this function is faster than quat4.inverse and produces the same result.
		 *
		 * @param {quat4} quat quat4 to calculate conjugate of
		 * @param {quat4} [dest] quat4 receiving conjugate values. If not specified result is written to quat
		 *
		 * @returns {quat4} dest if specified, quat otherwise
		 */
		quat4.conjugate = function (quat, dest) {
			if (!dest || quat === dest) {
				quat[0] *= -1;
				quat[1] *= -1;
				quat[2] *= -1;
				return quat;
			}
			dest[0] = -quat[0];
			dest[1] = -quat[1];
			dest[2] = -quat[2];
			dest[3] = quat[3];
			return dest;
		};

		/**
		 * Calculates the length of a quat4
		 *
		 * Params:
		 * @param {quat4} quat quat4 to calculate length of
		 *
		 * @returns Length of quat
		 */
		quat4.length = function (quat) {
			var x = quat[0], y = quat[1], z = quat[2], w = quat[3];
			return Math.sqrt(x * x + y * y + z * z + w * w);
		};

		/**
		 * Generates a unit quaternion of the same direction as the provided quat4
		 * If quaternion length is 0, returns [0, 0, 0, 0]
		 *
		 * @param {quat4} quat quat4 to normalize
		 * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat
		 *
		 * @returns {quat4} dest if specified, quat otherwise
		 */
		quat4.normalize = function (quat, dest) {
			if (!dest) { dest = quat; }

			var x = quat[0], y = quat[1], z = quat[2], w = quat[3],
				len = Math.sqrt(x * x + y * y + z * z + w * w);
			if (len === 0) {
				dest[0] = 0;
				dest[1] = 0;
				dest[2] = 0;
				dest[3] = 0;
				return dest;
			}
			len = 1 / len;
			dest[0] = x * len;
			dest[1] = y * len;
			dest[2] = z * len;
			dest[3] = w * len;

			return dest;
		};

		/**
		 * Performs quaternion addition
		 *
		 * @param {quat4} quat First operand
		 * @param {quat4} quat2 Second operand
		 * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat
		 *
		 * @returns {quat4} dest if specified, quat otherwise
		 */
		quat4.add = function (quat, quat2, dest) {
			if(!dest || quat === dest) {
				quat[0] += quat2[0];
				quat[1] += quat2[1];
				quat[2] += quat2[2];
				quat[3] += quat2[3];
				return quat;
			}
			dest[0] = quat[0]+quat2[0];
			dest[1] = quat[1]+quat2[1];
			dest[2] = quat[2]+quat2[2];
			dest[3] = quat[3]+quat2[3];
			return dest;
		};

		/**
		 * Performs a quaternion multiplication
		 *
		 * @param {quat4} quat First operand
		 * @param {quat4} quat2 Second operand
		 * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat
		 *
		 * @returns {quat4} dest if specified, quat otherwise
		 */
		quat4.multiply = function (quat, quat2, dest) {
			if (!dest) { dest = quat; }

			var qax = quat[0], qay = quat[1], qaz = quat[2], qaw = quat[3],
				qbx = quat2[0], qby = quat2[1], qbz = quat2[2], qbw = quat2[3];

			dest[0] = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
			dest[1] = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
			dest[2] = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
			dest[3] = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;

			return dest;
		};

		/**
		 * Transforms a vec3 with the given quaternion
		 *
		 * @param {quat4} quat quat4 to transform the vector with
		 * @param {vec3} vec vec3 to transform
		 * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec
		 *
		 * @returns dest if specified, vec otherwise
		 */
		quat4.multiplyVec3 = function (quat, vec, dest) {
			if (!dest) { dest = vec; }

			var x = vec[0], y = vec[1], z = vec[2],
				qx = quat[0], qy = quat[1], qz = quat[2], qw = quat[3],

				// calculate quat * vec
				ix = qw * x + qy * z - qz * y,
				iy = qw * y + qz * x - qx * z,
				iz = qw * z + qx * y - qy * x,
				iw = -qx * x - qy * y - qz * z;

			// calculate result * inverse quat
			dest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
			dest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
			dest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;

			return dest;
		};

		/**
		 * Multiplies the components of a quaternion by a scalar value
		 *
		 * @param {quat4} quat to scale
		 * @param {number} val Value to scale by
		 * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat
		 *
		 * @returns {quat4} dest if specified, quat otherwise
		 */
		quat4.scale = function (quat, val, dest) {
			if(!dest || quat === dest) {
				quat[0] *= val;
				quat[1] *= val;
				quat[2] *= val;
				quat[3] *= val;
				return quat;
			}
			dest[0] = quat[0]*val;
			dest[1] = quat[1]*val;
			dest[2] = quat[2]*val;
			dest[3] = quat[3]*val;
			return dest;
		};

		/**
		 * Calculates a 3x3 matrix from the given quat4
		 *
		 * @param {quat4} quat quat4 to create matrix from
		 * @param {mat3} [dest] mat3 receiving operation result
		 *
		 * @returns {mat3} dest if specified, a new mat3 otherwise
		 */
		quat4.toMat3 = function (quat, dest) {
			if (!dest) { dest = mat3.create(); }

			var x = quat[0], y = quat[1], z = quat[2], w = quat[3],
				x2 = x + x,
				y2 = y + y,
				z2 = z + z,

				xx = x * x2,
				xy = x * y2,
				xz = x * z2,
				yy = y * y2,
				yz = y * z2,
				zz = z * z2,
				wx = w * x2,
				wy = w * y2,
				wz = w * z2;

			dest[0] = 1 - (yy + zz);
			dest[1] = xy + wz;
			dest[2] = xz - wy;

			dest[3] = xy - wz;
			dest[4] = 1 - (xx + zz);
			dest[5] = yz + wx;

			dest[6] = xz + wy;
			dest[7] = yz - wx;
			dest[8] = 1 - (xx + yy);

			return dest;
		};

		/**
		 * Calculates a 4x4 matrix from the given quat4
		 *
		 * @param {quat4} quat quat4 to create matrix from
		 * @param {mat4} [dest] mat4 receiving operation result
		 *
		 * @returns {mat4} dest if specified, a new mat4 otherwise
		 */
		quat4.toMat4 = function (quat, dest) {
			if (!dest) { dest = mat4.create(); }

			var x = quat[0], y = quat[1], z = quat[2], w = quat[3],
				x2 = x + x,
				y2 = y + y,
				z2 = z + z,

				xx = x * x2,
				xy = x * y2,
				xz = x * z2,
				yy = y * y2,
				yz = y * z2,
				zz = z * z2,
				wx = w * x2,
				wy = w * y2,
				wz = w * z2;

			dest[0] = 1 - (yy + zz);
			dest[1] = xy + wz;
			dest[2] = xz - wy;
			dest[3] = 0;

			dest[4] = xy - wz;
			dest[5] = 1 - (xx + zz);
			dest[6] = yz + wx;
			dest[7] = 0;

			dest[8] = xz + wy;
			dest[9] = yz - wx;
			dest[10] = 1 - (xx + yy);
			dest[11] = 0;

			dest[12] = 0;
			dest[13] = 0;
			dest[14] = 0;
			dest[15] = 1;

			return dest;
		};

		/**
		 * Performs a spherical linear interpolation between two quat4
		 *
		 * @param {quat4} quat First quaternion
		 * @param {quat4} quat2 Second quaternion
		 * @param {number} slerp Interpolation amount between the two inputs
		 * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat
		 *
		 * @returns {quat4} dest if specified, quat otherwise
		 */
		quat4.slerp = function (quat, quat2, slerp, dest) {
			if (!dest) { dest = quat; }

			var cosHalfTheta = quat[0] * quat2[0] + quat[1] * quat2[1] + quat[2] * quat2[2] + quat[3] * quat2[3],
				halfTheta,
				sinHalfTheta,
				ratioA,
				ratioB;

			if (Math.abs(cosHalfTheta) >= 1.0) {
				if (dest !== quat) {
					dest[0] = quat[0];
					dest[1] = quat[1];
					dest[2] = quat[2];
					dest[3] = quat[3];
				}
				return dest;
			}

			halfTheta = Math.acos(cosHalfTheta);
			sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);

			if (Math.abs(sinHalfTheta) < 0.001) {
				dest[0] = (quat[0] * 0.5 + quat2[0] * 0.5);
				dest[1] = (quat[1] * 0.5 + quat2[1] * 0.5);
				dest[2] = (quat[2] * 0.5 + quat2[2] * 0.5);
				dest[3] = (quat[3] * 0.5 + quat2[3] * 0.5);
				return dest;
			}

			ratioA = Math.sin((1 - slerp) * halfTheta) / sinHalfTheta;
			ratioB = Math.sin(slerp * halfTheta) / sinHalfTheta;

			dest[0] = (quat[0] * ratioA + quat2[0] * ratioB);
			dest[1] = (quat[1] * ratioA + quat2[1] * ratioB);
			dest[2] = (quat[2] * ratioA + quat2[2] * ratioB);
			dest[3] = (quat[3] * ratioA + quat2[3] * ratioB);

			return dest;
		};

		/**
		 * Creates a quaternion from the given 3x3 rotation matrix.
		 * If dest is omitted, a new quaternion will be created.
		 *
		 * @param {mat3}  mat    the rotation matrix
		 * @param {quat4} [dest] an optional receiving quaternion
		 *
		 * @returns {quat4} the quaternion constructed from the rotation matrix
		 *
		 */
		quat4.fromRotationMatrix = function(mat, dest) {
			if (!dest) dest = quat4.create();
			
			// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
			// article "Quaternion Calculus and Fast Animation".

			var fTrace = mat[0] + mat[4] + mat[8];
			var fRoot;

			if ( fTrace > 0.0 ) {
				// |w| > 1/2, may as well choose w > 1/2
				fRoot = Math.sqrt(fTrace + 1.0);  // 2w
				dest[3] = 0.5 * fRoot;
				fRoot = 0.5/fRoot;  // 1/(4w)
				dest[0] = (mat[7]-mat[5])*fRoot;
				dest[1] = (mat[2]-mat[6])*fRoot;
				dest[2] = (mat[3]-mat[1])*fRoot;
			} else {
				// |w| <= 1/2
				var s_iNext = quat4.fromRotationMatrix.s_iNext = quat4.fromRotationMatrix.s_iNext || [1,2,0];
				var i = 0;
				if ( mat[4] > mat[0] )
				  i = 1;
				if ( mat[8] > mat[i*3+i] )
				  i = 2;
				var j = s_iNext[i];
				var k = s_iNext[j];
				
				fRoot = Math.sqrt(mat[i*3+i]-mat[j*3+j]-mat[k*3+k] + 1.0);
				dest[i] = 0.5 * fRoot;
				fRoot = 0.5 / fRoot;
				dest[3] = (mat[k*3+j] - mat[j*3+k]) * fRoot;
				dest[j] = (mat[j*3+i] + mat[i*3+j]) * fRoot;
				dest[k] = (mat[k*3+i] + mat[i*3+k]) * fRoot;
			}
			
			return dest;
		};

		/**
		 * Alias. See the description for quat4.fromRotationMatrix().
		 */
		mat3.toQuat4 = quat4.fromRotationMatrix;

		(function() {
			var mat = mat3.create();
			
			/**
			 * Creates a quaternion from the 3 given vectors. They must be perpendicular
			 * to one another and represent the X, Y and Z axes.
			 *
			 * If dest is omitted, a new quat4 will be created.
			 *
			 * Example: The default OpenGL orientation has a view vector [0, 0, -1],
			 * right vector [1, 0, 0], and up vector [0, 1, 0]. A quaternion representing
			 * this orientation could be constructed with:
			 *
			 *   quat = quat4.fromAxes([0, 0, -1], [1, 0, 0], [0, 1, 0], quat4.create());
			 *
			 * @param {vec3}  view   the view vector, or direction the object is pointing in
			 * @param {vec3}  right  the right vector, or direction to the "right" of the object
			 * @param {vec3}  up     the up vector, or direction towards the object's "up"
			 * @param {quat4} [dest] an optional receiving quat4
			 *
			 * @returns {quat4} dest
			 **/
			quat4.fromAxes = function(view, right, up, dest) {
				mat[0] = right[0];
				mat[3] = right[1];
				mat[6] = right[2];

				mat[1] = up[0];
				mat[4] = up[1];
				mat[7] = up[2];

				mat[2] = view[0];
				mat[5] = view[1];
				mat[8] = view[2];

				return quat4.fromRotationMatrix(mat, dest);
			};
		})();

		/**
		 * Sets a quat4 to the Identity and returns it.
		 *
		 * @param {quat4} [dest] quat4 to set. If omitted, a
		 * new quat4 will be created.
		 *
		 * @returns {quat4} dest
		 */
		quat4.identity = function(dest) {
			if (!dest) dest = quat4.create();
			dest[0] = 0;
			dest[1] = 0;
			dest[2] = 0;
			dest[3] = 1;
			return dest;
		};

		/**
		 * Sets a quat4 from the given angle and rotation axis,
		 * then returns it. If dest is not given, a new quat4 is created.
		 *
		 * @param {Number} angle  the angle in radians
		 * @param {vec3}   axis   the axis around which to rotate
		 * @param {quat4}  [dest] the optional quat4 to store the result
		 *
		 * @returns {quat4} dest
		 **/
		quat4.fromAngleAxis = function(angle, axis, dest) {
			// The quaternion representing the rotation is
			//   q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
			if (!dest) dest = quat4.create();
			
			var half = angle * 0.5;
			var s = Math.sin(half);
			dest[3] = Math.cos(half);
			dest[0] = s * axis[0];
			dest[1] = s * axis[1];
			dest[2] = s * axis[2];
			
			return dest;
		};

		/**
		 * Stores the angle and axis in a vec4, where the XYZ components represent
		 * the axis and the W (4th) component is the angle in radians.
		 *
		 * If dest is not given, src will be modified in place and returned, after
		 * which it should not be considered not a quaternion (just an axis and angle).
		 *
		 * @param {quat4} quat   the quaternion whose angle and axis to store
		 * @param {vec4}  [dest] the optional vec4 to receive the data
		 *
		 * @returns {vec4} dest
		 */
		quat4.toAngleAxis = function(src, dest) {
			if (!dest) dest = src;
			// The quaternion representing the rotation is
			//   q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)

			var sqrlen = src[0]*src[0]+src[1]*src[1]+src[2]*src[2];
			if (sqrlen > 0)
			{
				dest[3] = 2 * Math.acos(src[3]);
				var invlen = glMath.invsqrt(sqrlen);
				dest[0] = src[0]*invlen;
				dest[1] = src[1]*invlen;
				dest[2] = src[2]*invlen;
			} else {
				// angle is 0 (mod 2*pi), so any axis will do
				dest[3] = 0;
				dest[0] = 1;
				dest[1] = 0;
				dest[2] = 0;
			}
			
			return dest;
		};

		/**
		 * Returns a string representation of a quaternion
		 *
		 * @param {quat4} quat quat4 to represent as a string
		 *
		 * @returns {string} String representation of quat
		 */
		quat4.str = function (quat) {
			return '[' + quat[0] + ', ' + quat[1] + ', ' + quat[2] + ', ' + quat[3] + ']';
		};
		
		/**
		 * @class 2 Dimensional Vector
		 * @name vec2
		 */
		var vec2 = {};
		 
		/**
		 * Creates a new vec2, initializing it from vec if vec
		 * is given.
		 *
		 * @param {vec2} [vec] the vector's initial contents
		 * @returns {vec2} a new 2D vector
		 */
		vec2.create = function(vec) {
			var dest = new MatrixArray(2);

			if (vec) {
				dest[0] = vec[0];
				dest[1] = vec[1];
			} else {
				dest[0] = 0;
				dest[1] = 0;
			}
			return dest;
		};

		/**
		 * Creates a new instance of a vec2, initializing it with the given arguments
		 *
		 * @param {number} x X value
		 * @param {number} y Y value

		 * @returns {vec2} New vec2
		 */
		vec2.createFrom = function (x, y) {
			var dest = new MatrixArray(2);

			dest[0] = x;
			dest[1] = y;

			return dest;
		};
		
		/**
		 * Adds the vec2's together. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecB.
		 *
		 * @param {vec2} vecA the first operand
		 * @param {vec2} vecB the second operand
		 * @param {vec2} [dest] the optional receiving vector
		 * @returns {vec2} dest
		 */
		vec2.add = function(vecA, vecB, dest) {
			if (!dest) dest = vecB;
			dest[0] = vecA[0] + vecB[0];
			dest[1] = vecA[1] + vecB[1];
			return dest;
		};
		
		/**
		 * Subtracts vecB from vecA. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecB.
		 *
		 * @param {vec2} vecA the first operand
		 * @param {vec2} vecB the second operand
		 * @param {vec2} [dest] the optional receiving vector
		 * @returns {vec2} dest
		 */
		vec2.subtract = function(vecA, vecB, dest) {
			if (!dest) dest = vecB;
			dest[0] = vecA[0] - vecB[0];
			dest[1] = vecA[1] - vecB[1];
			return dest;
		};
		
		/**
		 * Multiplies vecA with vecB. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecB.
		 *
		 * @param {vec2} vecA the first operand
		 * @param {vec2} vecB the second operand
		 * @param {vec2} [dest] the optional receiving vector
		 * @returns {vec2} dest
		 */
		vec2.multiply = function(vecA, vecB, dest) {
			if (!dest) dest = vecB;
			dest[0] = vecA[0] * vecB[0];
			dest[1] = vecA[1] * vecB[1];
			return dest;
		};
		
		/**
		 * Divides vecA by vecB. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecB.
		 *
		 * @param {vec2} vecA the first operand
		 * @param {vec2} vecB the second operand
		 * @param {vec2} [dest] the optional receiving vector
		 * @returns {vec2} dest
		 */
		vec2.divide = function(vecA, vecB, dest) {
			if (!dest) dest = vecB;
			dest[0] = vecA[0] / vecB[0];
			dest[1] = vecA[1] / vecB[1];
			return dest;
		};
		
		/**
		 * Scales vecA by some scalar number. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecA.
		 *
		 * This is the same as multiplying each component of vecA
		 * by the given scalar.
		 *
		 * @param {vec2}   vecA the vector to be scaled
		 * @param {Number} scalar the amount to scale the vector by
		 * @param {vec2}   [dest] the optional receiving vector
		 * @returns {vec2} dest
		 */
		vec2.scale = function(vecA, scalar, dest) {
			if (!dest) dest = vecA;
			dest[0] = vecA[0] * scalar;
			dest[1] = vecA[1] * scalar;
			return dest;
		};

		/**
		 * Calculates the euclidian distance between two vec2
		 *
		 * Params:
		 * @param {vec2} vecA First vector
		 * @param {vec2} vecB Second vector
		 *
		 * @returns {number} Distance between vecA and vecB
		 */
		vec2.dist = function (vecA, vecB) {
			var x = vecB[0] - vecA[0],
				y = vecB[1] - vecA[1];
			return Math.sqrt(x*x + y*y);
		};

		/**
		 * Copies the values of one vec2 to another
		 *
		 * @param {vec2} vec vec2 containing values to copy
		 * @param {vec2} dest vec2 receiving copied values
		 *
		 * @returns {vec2} dest
		 */
		vec2.set = function (vec, dest) {
			dest[0] = vec[0];
			dest[1] = vec[1];
			return dest;
		};

		/**
		 * Negates the components of a vec2
		 *
		 * @param {vec2} vec vec2 to negate
		 * @param {vec2} [dest] vec2 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec2} dest if specified, vec otherwise
		 */
		vec2.negate = function (vec, dest) {
			if (!dest) { dest = vec; }
			dest[0] = -vec[0];
			dest[1] = -vec[1];
			return dest;
		};

		/**
		 * Normlize a vec2
		 *
		 * @param {vec2} vec vec2 to normalize
		 * @param {vec2} [dest] vec2 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec2} dest if specified, vec otherwise
		 */
		vec2.normalize = function (vec, dest) {
			if (!dest) { dest = vec; }
			var mag = vec[0] * vec[0] + vec[1] * vec[1];
			if (mag > 0) {
				mag = Math.sqrt(mag);
				dest[0] = vec[0] / mag;
				dest[1] = vec[1] / mag;
			} else {
				dest[0] = dest[1] = 0;
			}
			return dest;
		};

		/**
		 * Computes the cross product of two vec2's. Note that the cross product must by definition
		 * produce a 3D vector. If a dest vector is given, it will contain the resultant 3D vector.
		 * Otherwise, a scalar number will be returned, representing the vector's Z coordinate, since
		 * its X and Y must always equal 0.
		 *
		 * Examples:
		 *    var crossResult = vec3.create();
		 *    vec2.cross([1, 2], [3, 4], crossResult);
		 *    //=> [0, 0, -2]
		 *
		 *    vec2.cross([1, 2], [3, 4]);
		 *    //=> -2
		 *
		 * See http://stackoverflow.com/questions/243945/calculating-a-2d-vectors-cross-product
		 * for some interesting facts.
		 *
		 * @param {vec2} vecA left operand
		 * @param {vec2} vecB right operand
		 * @param {vec2} [dest] optional vec2 receiving result. If not specified a scalar is returned
		 *
		 */
		vec2.cross = function (vecA, vecB, dest) {
			var z = vecA[0] * vecB[1] - vecA[1] * vecB[0];
			if (!dest) return z;
			dest[0] = dest[1] = 0;
			dest[2] = z;
			return dest;
		};
		
		/**
		 * Caclulates the length of a vec2
		 *
		 * @param {vec2} vec vec2 to calculate length of
		 *
		 * @returns {Number} Length of vec
		 */
		vec2.length = function (vec) {
		  var x = vec[0], y = vec[1];
		  return Math.sqrt(x * x + y * y);
		};

		/**
		 * Caclulates the dot product of two vec2s
		 *
		 * @param {vec3} vecA First operand
		 * @param {vec3} vecB Second operand
		 *
		 * @returns {Number} Dot product of vecA and vecB
		 */
		vec2.dot = function (vecA, vecB) {
			return vecA[0] * vecB[0] + vecA[1] * vecB[1];
		};
		
		/**
		 * Generates a 2D unit vector pointing from one vector to another
		 *
		 * @param {vec2} vecA Origin vec2
		 * @param {vec2} vecB vec2 to point to
		 * @param {vec2} [dest] vec2 receiving operation result. If not specified result is written to vecA
		 *
		 * @returns {vec2} dest if specified, vecA otherwise
		 */
		vec2.direction = function (vecA, vecB, dest) {
			if (!dest) { dest = vecA; }

			var x = vecA[0] - vecB[0],
				y = vecA[1] - vecB[1],
				len = x * x + y * y;

			if (!len) {
				dest[0] = 0;
				dest[1] = 0;
				dest[2] = 0;
				return dest;
			}

			len = 1 / Math.sqrt(len);
			dest[0] = x * len;
			dest[1] = y * len;
			return dest;
		};

		/**
		 * Performs a linear interpolation between two vec2
		 *
		 * @param {vec2} vecA First vector
		 * @param {vec2} vecB Second vector
		 * @param {Number} lerp Interpolation amount between the two inputs
		 * @param {vec2} [dest] vec2 receiving operation result. If not specified result is written to vecA
		 *
		 * @returns {vec2} dest if specified, vecA otherwise
		 */
		vec2.lerp = function (vecA, vecB, lerp, dest) {
			if (!dest) { dest = vecA; }
			dest[0] = vecA[0] + lerp * (vecB[0] - vecA[0]);
			dest[1] = vecA[1] + lerp * (vecB[1] - vecA[1]);
			return dest;
		};

		/**
		 * Returns a string representation of a vector
		 *
		 * @param {vec2} vec Vector to represent as a string
		 *
		 * @returns {String} String representation of vec
		 */
		vec2.str = function (vec) {
			return '[' + vec[0] + ', ' + vec[1] + ']';
		};
		
		/**
		 * @class 2x2 Matrix
		 * @name mat2
		 */
		var mat2 = {};
		
		/**
		 * Creates a new 2x2 matrix. If src is given, the new matrix
		 * is initialized to those values.
		 *
		 * @param {mat2} [src] the seed values for the new matrix, if any
		 * @returns {mat2} a new matrix
		 */
		mat2.create = function(src) {
			var dest = new MatrixArray(4);
			
			if (src) {
				dest[0] = src[0];
				dest[1] = src[1];
				dest[2] = src[2];
				dest[3] = src[3];
			} else {
				dest[0] = dest[1] = dest[2] = dest[3] = 0;
			}
			return dest;
		};

		/**
		 * Creates a new instance of a mat2, initializing it with the given arguments
		 *
		 * @param {number} m00
		 * @param {number} m01
		 * @param {number} m10
		 * @param {number} m11

		 * @returns {mat2} New mat2
		 */
		mat2.createFrom = function (m00, m01, m10, m11) {
			var dest = new MatrixArray(4);

			dest[0] = m00;
			dest[1] = m01;
			dest[2] = m10;
			dest[3] = m11;

			return dest;
		};
		
		/**
		 * Copies the values of one mat2 to another
		 *
		 * @param {mat2} mat mat2 containing values to copy
		 * @param {mat2} dest mat2 receiving copied values
		 *
		 * @returns {mat2} dest
		 */
		mat2.set = function (mat, dest) {
			dest[0] = mat[0];
			dest[1] = mat[1];
			dest[2] = mat[2];
			dest[3] = mat[3];
			return dest;
		};

		/**
		 * Sets a mat2 to an identity matrix
		 *
		 * @param {mat2} [dest] mat2 to set. If omitted a new one will be created.
		 *
		 * @returns {mat2} dest
		 */
		mat2.identity = function (dest) {
			if (!dest) { dest = mat2.create(); }
			dest[0] = 1;
			dest[1] = 0;
			dest[2] = 0;
			dest[3] = 1;
			return dest;
		};

		/**
		 * Transposes a mat2 (flips the values over the diagonal)
		 *
		 * @param {mat2} mat mat2 to transpose
		 * @param {mat2} [dest] mat2 receiving transposed values. If not specified result is written to mat
		 *
		 * @param {mat2} dest if specified, mat otherwise
		 */
		mat2.transpose = function (mat, dest) {
			// If we are transposing ourselves we can skip a few steps but have to cache some values
			if (!dest || mat === dest) {
				var a00 = mat[1];
				mat[1] = mat[2];
				mat[2] = a00;
				return mat;
			}
			
			dest[0] = mat[0];
			dest[1] = mat[2];
			dest[2] = mat[1];
			dest[3] = mat[3];
			return dest;
		};

		/**
		 * Calculates the determinant of a mat2
		 *
		 * @param {mat2} mat mat2 to calculate determinant of
		 *
		 * @returns {Number} determinant of mat
		 */
		mat2.determinant = function (mat) {
		  return mat[0] * mat[3] - mat[2] * mat[1];
		};
		
		/**
		 * Calculates the inverse matrix of a mat2
		 *
		 * @param {mat2} mat mat2 to calculate inverse of
		 * @param {mat2} [dest] mat2 receiving inverse matrix. If not specified result is written to mat
		 *
		 * @param {mat2} dest is specified, mat otherwise, null if matrix cannot be inverted
		 */
		mat2.inverse = function (mat, dest) {
			if (!dest) { dest = mat; }
			var a0 = mat[0], a1 = mat[1], a2 = mat[2], a3 = mat[3];
			var det = a0 * a3 - a2 * a1;
			if (!det) return null;
			
			det = 1.0 / det;
			dest[0] =  a3 * det;
			dest[1] = -a1 * det;
			dest[2] = -a2 * det;
			dest[3] =  a0 * det;
			return dest;
		};
		
		/**
		 * Performs a matrix multiplication
		 *
		 * @param {mat2} matA First operand
		 * @param {mat2} matB Second operand
		 * @param {mat2} [dest] mat2 receiving operation result. If not specified result is written to matA
		 *
		 * @returns {mat2} dest if specified, matA otherwise
		 */
		mat2.multiply = function (matA, matB, dest) {
			if (!dest) { dest = matA; }
			var a11 = matA[0],
				a12 = matA[1],
				a21 = matA[2],
				a22 = matA[3];
			dest[0] = a11 * matB[0] + a12 * matB[2];
			dest[1] = a11 * matB[1] + a12 * matB[3];
			dest[2] = a21 * matB[0] + a22 * matB[2];
			dest[3] = a21 * matB[1] + a22 * matB[3];
			return dest;
		};

		/**
		 * Rotates a 2x2 matrix by an angle
		 *
		 * @param {mat2}   mat   The matrix to rotate
		 * @param {Number} angle The angle in radians
		 * @param {mat2} [dest]  Optional mat2 receiving the result. If omitted mat will be used.
		 *
		 * @returns {mat2} dest if specified, mat otherwise
		 */
		mat2.rotate = function (mat, angle, dest) {
			if (!dest) { dest = mat; }
			var a11 = mat[0],
				a12 = mat[1],
				a21 = mat[2],
				a22 = mat[3],
				s = Math.sin(angle),
				c = Math.cos(angle);
			dest[0] = a11 *  c + a12 * s;
			dest[1] = a11 * -s + a12 * c;
			dest[2] = a21 *  c + a22 * s;
			dest[3] = a21 * -s + a22 * c;
			return dest;
		};

		/**
		 * Multiplies the vec2 by the given 2x2 matrix
		 *
		 * @param {mat2} matrix the 2x2 matrix to multiply against
		 * @param {vec2} vec    the vector to multiply
		 * @param {vec2} [dest] an optional receiving vector. If not given, vec is used.
		 *
		 * @returns {vec2} The multiplication result
		 **/
		mat2.multiplyVec2 = function(matrix, vec, dest) {
		  if (!dest) dest = vec;
		  var x = vec[0], y = vec[1];
		  dest[0] = x * matrix[0] + y * matrix[1];
		  dest[1] = x * matrix[2] + y * matrix[3];
		  return dest;
		};
		
		/**
		 * Scales the mat2 by the dimensions in the given vec2
		 *
		 * @param {mat2} matrix the 2x2 matrix to scale
		 * @param {vec2} vec    the vector containing the dimensions to scale by
		 * @param {vec2} [dest] an optional receiving mat2. If not given, matrix is used.
		 *
		 * @returns {mat2} dest if specified, matrix otherwise
		 **/
		mat2.scale = function(matrix, vec, dest) {
		  if (!dest) { dest = matrix; }
		  var a11 = matrix[0],
			  a12 = matrix[1],
			  a21 = matrix[2],
			  a22 = matrix[3],
			  b11 = vec[0],
			  b22 = vec[1];
		  dest[0] = a11 * b11;
		  dest[1] = a12 * b22;
		  dest[2] = a21 * b11;
		  dest[3] = a22 * b22;
		  return dest;
		};

		/**
		 * Returns a string representation of a mat2
		 *
		 * @param {mat2} mat mat2 to represent as a string
		 *
		 * @param {String} String representation of mat
		 */
		mat2.str = function (mat) {
			return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + ', ' + mat[3] + ']';
		};
		
		/**
		 * @class 4 Dimensional Vector
		 * @name vec4
		 */
		var vec4 = {};
		 
		/**
		 * Creates a new vec4, initializing it from vec if vec
		 * is given.
		 *
		 * @param {vec4} [vec] the vector's initial contents
		 * @returns {vec4} a new 2D vector
		 */
		vec4.create = function(vec) {
			var dest = new MatrixArray(4);
			
			if (vec) {
				dest[0] = vec[0];
				dest[1] = vec[1];
				dest[2] = vec[2];
				dest[3] = vec[3];
			} else {
				dest[0] = 0;
				dest[1] = 0;
				dest[2] = 0;
				dest[3] = 0;
			}
			return dest;
		};

		/**
		 * Creates a new instance of a vec4, initializing it with the given arguments
		 *
		 * @param {number} x X value
		 * @param {number} y Y value
		 * @param {number} z Z value
		 * @param {number} w W value

		 * @returns {vec4} New vec4
		 */
		vec4.createFrom = function (x, y, z, w) {
			var dest = new MatrixArray(4);

			dest[0] = x;
			dest[1] = y;
			dest[2] = z;
			dest[3] = w;

			return dest;
		};
		
		/**
		 * Adds the vec4's together. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecB.
		 *
		 * @param {vec4} vecA the first operand
		 * @param {vec4} vecB the second operand
		 * @param {vec4} [dest] the optional receiving vector
		 * @returns {vec4} dest
		 */
		vec4.add = function(vecA, vecB, dest) {
		  if (!dest) dest = vecB;
		  dest[0] = vecA[0] + vecB[0];
		  dest[1] = vecA[1] + vecB[1];
		  dest[2] = vecA[2] + vecB[2];
		  dest[3] = vecA[3] + vecB[3];
		  return dest;
		};
		
		/**
		 * Subtracts vecB from vecA. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecB.
		 *
		 * @param {vec4} vecA the first operand
		 * @param {vec4} vecB the second operand
		 * @param {vec4} [dest] the optional receiving vector
		 * @returns {vec4} dest
		 */
		vec4.subtract = function(vecA, vecB, dest) {
		  if (!dest) dest = vecB;
		  dest[0] = vecA[0] - vecB[0];
		  dest[1] = vecA[1] - vecB[1];
		  dest[2] = vecA[2] - vecB[2];
		  dest[3] = vecA[3] - vecB[3];
		  return dest;
		};
		
		/**
		 * Multiplies vecA with vecB. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecB.
		 *
		 * @param {vec4} vecA the first operand
		 * @param {vec4} vecB the second operand
		 * @param {vec4} [dest] the optional receiving vector
		 * @returns {vec4} dest
		 */
		vec4.multiply = function(vecA, vecB, dest) {
		  if (!dest) dest = vecB;
		  dest[0] = vecA[0] * vecB[0];
		  dest[1] = vecA[1] * vecB[1];
		  dest[2] = vecA[2] * vecB[2];
		  dest[3] = vecA[3] * vecB[3];
		  return dest;
		};
		
		/**
		 * Divides vecA by vecB. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecB.
		 *
		 * @param {vec4} vecA the first operand
		 * @param {vec4} vecB the second operand
		 * @param {vec4} [dest] the optional receiving vector
		 * @returns {vec4} dest
		 */
		vec4.divide = function(vecA, vecB, dest) {
		  if (!dest) dest = vecB;
		  dest[0] = vecA[0] / vecB[0];
		  dest[1] = vecA[1] / vecB[1];
		  dest[2] = vecA[2] / vecB[2];
		  dest[3] = vecA[3] / vecB[3];
		  return dest;
		};
		
		/**
		 * Scales vecA by some scalar number. If dest is given, the result
		 * is stored there. Otherwise, the result is stored in vecA.
		 *
		 * This is the same as multiplying each component of vecA
		 * by the given scalar.
		 *
		 * @param {vec4}   vecA the vector to be scaled
		 * @param {Number} scalar the amount to scale the vector by
		 * @param {vec4}   [dest] the optional receiving vector
		 * @returns {vec4} dest
		 */
		vec4.scale = function(vecA, scalar, dest) {
		  if (!dest) dest = vecA;
		  dest[0] = vecA[0] * scalar;
		  dest[1] = vecA[1] * scalar;
		  dest[2] = vecA[2] * scalar;
		  dest[3] = vecA[3] * scalar;
		  return dest;
		};

		/**
		 * Copies the values of one vec4 to another
		 *
		 * @param {vec4} vec vec4 containing values to copy
		 * @param {vec4} dest vec4 receiving copied values
		 *
		 * @returns {vec4} dest
		 */
		vec4.set = function (vec, dest) {
			dest[0] = vec[0];
			dest[1] = vec[1];
			dest[2] = vec[2];
			dest[3] = vec[3];
			return dest;
		};

		/**
		 * Negates the components of a vec4
		 *
		 * @param {vec4} vec vec4 to negate
		 * @param {vec4} [dest] vec4 receiving operation result. If not specified result is written to vec
		 *
		 * @returns {vec4} dest if specified, vec otherwise
		 */
		vec4.negate = function (vec, dest) {
			if (!dest) { dest = vec; }
			dest[0] = -vec[0];
			dest[1] = -vec[1];
			dest[2] = -vec[2];
			dest[3] = -vec[3];
			return dest;
		};

		/**
		 * Performs a linear interpolation between two vec4
		 *
		 * @param {vec4} vecA First vector
		 * @param {vec4} vecB Second vector
		 * @param {Number} lerp Interpolation amount between the two inputs
		 * @param {vec4} [dest] vec4 receiving operation result. If not specified result is written to vecA
		 *
		 * @returns {vec4} dest if specified, vecA otherwise
		 */
		vec4.lerp = function (vecA, vecB, lerp, dest) {
			if (!dest) { dest = vecA; }
			dest[0] = vecA[0] + lerp * (vecB[0] - vecA[0]);
			dest[1] = vecA[1] + lerp * (vecB[1] - vecA[1]);
			dest[2] = vecA[2] + lerp * (vecB[2] - vecA[2]);
			dest[3] = vecA[3] + lerp * (vecB[3] - vecA[3]);
			return dest;
		};

		/**
		 * Returns a string representation of a vector
		 *
		 * @param {vec4} vec Vector to represent as a string
		 *
		 * @returns {String} String representation of vec
		 */
		vec4.str = function (vec) {
			return '[' + vec[0] + ', ' + vec[1] + ', ' + vec[2] + ', ' + vec[3] + ']';
		};

		/*
		 * Exports
		 */

		if(root) {
			root.glMatrixArrayType = MatrixArray;
			root.MatrixArray = MatrixArray;
			root.setMatrixArrayType = setMatrixArrayType;
			root.determineMatrixArrayType = determineMatrixArrayType;
			root.glMath = glMath;
			root.vec2 = vec2;
			root.vec3 = vec3;
			root.vec4 = vec4;
			root.mat2 = mat2;
			root.mat3 = mat3;
			root.mat4 = mat4;
			root.quat4 = quat4;
		}

		return {
			glMatrixArrayType: MatrixArray,
			MatrixArray: MatrixArray,
			setMatrixArrayType: setMatrixArrayType,
			determineMatrixArrayType: determineMatrixArrayType,
			glMath: glMath,
			vec2: vec2,
			vec3: vec3,
			vec4: vec4,
			mat2: mat2,
			mat3: mat3,
			mat4: mat4,
			quat4: quat4
		};
	}));
	
	/*
		Copyright (c) 2012 Alexander Overvoorde

		Permission is hereby granted, free of charge, to any person obtaining
		a copy of this software and associated documentation files (the
		"Software"), to deal in the Software without restriction, including
		without limitation the rights to use, copy, modify, merge, publish,
		distribute, sublicense, and/or sell copies of the Software, and to
		permit persons to whom the Software is furnished to do so, subject to
		the following conditions:

		The above copyright notice and this permission notice shall be
		included in all copies or substantial portions of the Software.

		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
		EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
		MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
		NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
		LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
		OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
		WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
	*/

	/*
		Constants
	*/

	GL = {};

	// Begin modes
	GL.POINTS				= 0x0000;
	GL.LINES				= 0x0001;
	GL.TRIANGLES			= 0x0004;
	GL.QUADS				= 0x0007;

	// Errors
	GL.NO_ERROR				= 0x0000;
	GL.INVALID_ENUM			= 0x0500;
	GL.INVALID_VALUE		= 0x0501;
	GL.INVALID_OPERATION	= 0x0502;

	// Features
	GL.DEPTH_TEST			= 0x0B71;
	GL.CULL_FACE			= 0x0B44;
	GL.TEXTURE_2D			= 0x0DE1;

	// Types
	GL.BYTE					= 0x1400;
	GL.FLOAT				= 0x1406;
	GL.UNSIGNED_BYTE_2_3_3	= 0xFFFF; // Extension to support JSOS

	// Matrix modes
	GL.MODELVIEW			= 0x1700;
	GL.PROJECTION			= 0x1701;

	// Pixel formats
	GL.DEPTH_COMPONENT		= 0x1902;
	GL.RGB					= 0x1907;
	GL.RGBA					= 0x1908;

	// Buffers
	GL.DEPTH_BUFFER_BIT		= 0x0100;
	GL.COLOR_BUFFER_BIT 	= 0x4000;


	/*
		Creates a new instance of a software OpenGL 1.1 context.

		w	Width of the frame buffer.
		h	Height of the frame buffer.
	*/

	GL.Context = function( w, h )
	{
		// Initialize buffers
		this.w = w;
		this.h = h;
		this.bufColor = [];
		this.bufDepth = [];

		// Initialize matrix stack
		this.matModelView = mat4.create();
		this.matProj = mat4.create();
		this.curMatrix = this.matModelView;

		// Set error
		this.err = GL.NO_ERROR;

		// Initialize rest of the state
		this.bufColorClear = [ 0.0, 0.0, 0.0, 1.0 ];
		this.bufDepthClear = 1.0;

		this.beginMode = -1;
		this.beginColor = [ 1.0, 1.0, 1.0, 1.0 ];
		this.beginTexCoord = [ 0.0, 0.0 ];

		this.textures = [];
		this.curTexture = 0;

		this.depthEnabled = false;
		this.cullingEnabled = false;
		this.textureEnabled = false;
	};

	/*
		Enables or disables OpenGL capabilities.
	*/

	GL.Context.prototype.enable = function( capability )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( capability !== GL.DEPTH_TEST && capability !== GL.CULL_FACE && capability !== GL.TEXTURE_2D ) {
			this.err = GL.INVALID_ENUM;
			return null;
		}

		if ( capability == GL.DEPTH_TEST ) this.depthEnabled = true;
		else if ( capability == GL.CULL_FACE ) this.cullingEnabled = true;
		else if ( capability == GL.TEXTURE_2D ) this.textureEnabled = true;
	};

	GL.Context.prototype.disable = function( capability )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( capability !== GL.DEPTH_TEST && capability !== GL.CULL_FACE && capability !== GL.TEXTURE_2D ) {
			this.err = GL.INVALID_ENUM;
			return null;
		}

		if ( capability == GL.DEPTH_TEST ) this.depthEnabled = false;
		else if ( capability == GL.CULL_FACE ) this.cullingEnabled = false;
		else if ( capability == GL.TEXTURE_2D ) this.textureEnabled = false;
	};

	/*
		Returns any errors caused by the last function call.
	*/

	GL.Context.prototype.getError = function()
	{
		if ( this.beginMode !== -1 ) return 0;
		return this.err;
	};

	/*
		Sets the color buffer clear color.

		r, g, b 	Color components
		a 			Alpha component
	*/

	GL.Context.prototype.clearColor = function( r, g, b, a )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}

		this.bufColorClear = [ fclamp( r ), fclamp( g ), fclamp( b ), fclamp( a ) ];
	};

	/*
		Sets the depth buffer clear color.
	*/

	GL.Context.prototype.clearDepth = function( depth )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}

		this.bufDepthClear = depth;
	};

	/*
		Clears one or more buffers.
	*/

	GL.Context.prototype.clear = function( mask )
	{
		if ( mask - GL.COLOR_BUFFER_BIT - GL.DEPTH_BUFFER_BIT > 0 ) {
			this.err = GL.INVALID_VALUE;
			return null;
		}

		if ( ( mask & GL.COLOR_BUFFER_BIT ) !== 0 ) {
			var size = this.w*this.h*4;
			for ( var i = 0; i < size; i++ ) {
				this.bufColor[i] = this.bufColorClear[i%4];
			}
		}
		if ( ( mask & GL.DEPTH_BUFFER_BIT ) !== 0 ) {
			var size = this.w*this.h;
			for ( var i = 0; i < size; i++ ) {
				this.bufDepth[i] = this.bufDepthClear;
			}
		}
	};

	/*
		Start specification of vertices belonging to a group of primitives.
	*/

	GL.Context.prototype.begin = function( mode )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( mode !== GL.POINTS && mode !== GL.LINES && mode !== GL.TRIANGLES && mode !== GL.QUADS ) {
			this.err = GL.INVALID_ENUM;
			return null;
		}

		this.beginMode = mode;
		this.beginVertices = [];
	};

	/*
		Finish specification of vertices.
	*/

	GL.Context.prototype.end = function()
	{
		if ( this.beginMode == -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}

		// Transform vertices and map them to window coordinates
		for ( var i = 0; i < this.beginVertices.length; i++ ) {
			var vertex = this.beginVertices[i];

			// Transform vertex into eye space
			var vec = [ vertex[0], vertex[1], vertex[2], 1 ];
			mat4.multiplyVec4( this.matModelView, vec );

			// Perform backface culling - if enabled
			if ( this.cullingEnabled && ( ( this.beginMode == GL.QUADS && i % 4 == 0 ) || ( this.beginMode == GL.TRIANGLES && i % 3 == 0 ) ) ) {
				var side1 = vec3.create();
				vec3.subtract( this.beginVertices[i], this.beginVertices[i+1], side1 );
				var side2 = vec3.create();
				vec3.subtract( this.beginVertices[i], this.beginVertices[i+2], side2 );
				var normal = vec3.create();
				vec3.cross( side1, side2, normal );
				var dot = vec3.dot( normal, this.beginVertices[i] );
				vertex[5] = dot <= 0; // If dot > 0, then face is facing away from camera
			}

			// Transform vertex into clip space
			mat4.multiplyVec4( this.matProj, vec );

			// Calculate normalized device coordinates
			var norm = [];
			norm[0] = vec[0] / vec[3];
			norm[1] = vec[1] / vec[3];
			norm[2] = vec[2] / vec[3];

			vertex[0] = (norm[0]+1)/2*this.w;
			vertex[1] = (1-norm[1])/2*this.h;
			vertex[2] = norm[2];

			this.beginVertices[i] = vertex;
		}

		// Assemble primitives
		if ( this.beginMode == GL.POINTS )
			for ( var i = 0; i < this.beginVertices.length; i += 1 ) drawPoint( this.beginVertices[i], this.bufColor, this.bufDepth, this );
		else if ( this.beginMode == GL.LINES && this.beginVertices.length >= 2 )
			for ( var i = 0; i < this.beginVertices.length; i += 2 ) drawLine( [ this.beginVertices[i], this.beginVertices[i+1] ], this.bufColor, this.bufDepth, this );
		else if ( this.beginMode == GL.TRIANGLES && this.beginVertices.length >= 3 )
			for ( var i = 0; i < this.beginVertices.length; i += 3 ) drawTriangle( [ this.beginVertices[i], this.beginVertices[i+1], this.beginVertices[i+2] ], this.bufColor, this.bufDepth, this );
		else if ( this.beginMode == GL.QUADS && this.beginVertices.length >= 4 )
			for ( var i = 0; i < this.beginVertices.length; i += 4 ) drawQuad( [ this.beginVertices[i], this.beginVertices[i+1], this.beginVertices[i+2], this.beginVertices[i+3] ], this.bufColor, this.bufDepth, this );

		this.beginMode = -1;
		this.beginVertices = null;
	};

	/*
		Set the current color.
	*/

	GL.Context.prototype.color4f = function( r, g, b, a )
	{
		this.beginColor = [ fclamp( r ), fclamp( g ), fclamp( b ), fclamp( a ) ];
	};

	GL.Context.prototype.color3f = function( r, g, b )
	{
		return this.color4f( r, g, b, 1.0 );
	};

	/*
		Specify a 2D texture coordinate.
	*/

	GL.Context.prototype.texCoord2f = function( u, v )
	{
		this.beginTexCoord = [ u, v ];
	};

	/*
		Specify a vertex.
	*/

	GL.Context.prototype.vertex3f = function( x, y, z )
	{
		if ( this.beginMode == -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}

		this.beginVertices.push( [ x, y, z, this.beginColor, this.beginTexCoord ] );
	};

	/*
		Specify which matrix to apply operations on.
	*/

	GL.Context.prototype.matrixMode = function( mode )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( mode !== GL.MODELVIEW && mode !== GL.PROJECTION ) {
			this.err = GL.INVALID_ENUM;
			return null;
		}

		this.curMatrix = mode == GL.MODELVIEW ? this.matModelView : this.matProj;
	};

	/*
		Replaces the current matrix with the identity matrix.
	*/

	GL.Context.prototype.loadIdentity = function()
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}

		mat4.identity( this.curMatrix );
	};

	/*
		Multiplies the current matrix by a translation matrix.
	*/

	GL.Context.prototype.translatef = function( x, y, z )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}

		mat4.translate( this.curMatrix, [ x, y, z ] );
	};

	/*
		Multiplies the current matrix by a scale matrix.
	*/

	GL.Context.prototype.scalef = function( x, y, z )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}

		mat4.scale( this.curMatrix, [ x, y, z ] );
	};

	/*
		Multiplies the current matrix by a rotation matrix.
	*/

	GL.Context.prototype.rotatef = function( angle, x, y, z )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}

		mat4.rotate( this.curMatrix, angle, [ x, y, z ] );
	};

	/*
		Sets up a perspective projection matrix.
	*/

	GL.Context.prototype.perspective = function( fovy, aspect, near, far )
	{
		mat4.perspective( fovy, aspect, near, far, this.curMatrix );
	};

	/*
		Defines a viewing transformation.
	*/

	GL.Context.prototype.lookAt = function( eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ )
	{
		mat4.lookAt( [ eyeX, eyeY, eyeZ ], [ centerX, centerY, centerZ ], [ upX, upY, upZ ], this.curMatrix );
	};

	/*
		Generate texture objects.
	*/

	GL.Context.prototype.genTextures = function( count, buf )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( count < 0 ) {
			this.err = GL.INVALID_VALUE;
			return null;
		}

		for ( var i = 0; i < count; i++ ) {
			var j = this.textures.length + 1;
			buf[i] = j;
			this.textures[j-1] = { pixels: null, w: 0, h: 0 };
		}
	};

	/*
		Make a texture current.
	*/

	GL.Context.prototype.bindTexture = function( target, id )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( target !== GL.TEXTURE_2D ) {
			this.err = GL.INVALID_ENUM;
			return null;
		}

		if ( target == GL.TEXTURE_2D ) this.curTexture = id - 1;
	};

	/*
		Specify the pixels for a texture image.
	*/

	GL.Context.prototype.texImage2D = function( target, width, height, type, data )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( target !== GL.TEXTURE_2D ) {
			this.err = GL.INVALID_ENUM;
			return null;
		}
		if ( type !== GL.BYTE && type !== GL.FLOAT ) {
			this.err = GL.INVALID_ENUM;
			return null;
		}

		var texture = this.textures[this.curTexture];
		if ( texture == undefined ) return;
		texture.pixels = [];
		texture.w = width;
		texture.h = height;

		var size = width*height*4;
		for ( var i = 0; i < size; i += 4 ) {
			texture.pixels[i+0] = data[i+0] / ( type == GL.BYTE ? 255 : 1 );
			texture.pixels[i+1] = data[i+1] / ( type == GL.BYTE ? 255 : 1 );
			texture.pixels[i+2] = data[i+2] / ( type == GL.BYTE ? 255 : 1 );
			texture.pixels[i+3] = data[i+3] / ( type == GL.BYTE ? 255 : 1 );
		}
	};

	/*
		Reads pixels from a buffer and returns them as an array.

		x, y	Window coordinates of the area you want to capture.
		w, h	Size of the area you want to capture.
	*/

	GL.Context.prototype.readPixels = function( x, y, w, h, format, type, data )
	{
		if ( this.beginMode !== -1 ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( ( format !== GL.RGBA && format !== GL.RGB && format !== GL.DEPTH_COMPONENT ) || ( type !== GL.BYTE && type !== GL.FLOAT && type !== GL.UNSIGNED_BYTE_2_3_3 ) ) {
			this.err = GL.INVALID_ENUM;
			return null;
		}
		if ( ( type == GL.UNSIGNED_BYTE_2_3_3 && format !== GL.RGB ) || ( format == GL.RGB && type !== GL.UNSIGNED_BYTE_2_3_3 ) ) {
			this.err = GL.INVALID_OPERATION;
			return null;
		}
		if ( w < 0 || h < 0 ) {
			this.err = GL.INVALID_VALUE;
			return null;
		}

		if ( format == GL.RGBA ) {
			var size = this.w*this.h*4;
			for ( var i = 0; i < size; i += 4 ) {
				data[i+0] = this.bufColor[i+0] * ( type == GL.BYTE ? 255 : 1 );
				data[i+1] = this.bufColor[i+1] * ( type == GL.BYTE ? 255 : 1 );
				data[i+2] = this.bufColor[i+2] * ( type == GL.BYTE ? 255 : 1 );
				data[i+3] = this.bufColor[i+3] * ( type == GL.BYTE ? 255 : 1 );
			}
		} else if ( format == GL.RGB ) {
			var size = this.w*this.h*4;
			for ( var i = 0; i < size; i += 4 ) {
				var color = (((this.bufColor[i+0]*255) & 0xc0) >> 0) | (((this.bufColor[i+1]*255) & 0xe0) >> 2) | (((this.bufColor[i+2]*255) & 0xe0) >> 5);
				data[i/4] = color;
			}
		} else if ( format == GL.DEPTH_COMPONENT ) {
			var size = this.w*this.h;
			for ( var i = 0; i < size; i++ )
				data[i+0] = this.bufDepth[i] * ( type == GL.BYTE ? 255 : 1 );
		}
	};

	/*
		Draw a point to the specified pixel array.
	*/

	function drawPoint( p, color, depth, gl )
	{
		var o = (Math.floor(p[0])+Math.floor(p[1])*gl.w)*4;

		if ( gl.depthEnabled ) {
			var d = p[2];
			if ( d > depth[o/4] ) return;
			else depth[o/4] = d;
		}

		// Vertex color
		var fragColor = [];
		fragColor[0] = p[3][0];
		fragColor[1] = p[3][1];
		fragColor[2] = p[3][2];
		fragColor[3] = p[3][3];

		// Texture sample
		var tex = gl.textures[gl.curTexture];
		if ( gl.textureEnabled && tex !== undefined ) {
			var u = p[4][0];
			var v = p[4][1];
			u = Math.floor( u * tex.w ) % tex.w; // This behaviour should later depend on GL_TEXTURE_WRAP_S
			v = Math.floor( v * tex.h ) % tex.h;

			var to = (u+v*tex.w)*4;
			fragColor[0] *= tex.pixels[to+0];
			fragColor[1] *= tex.pixels[to+1];
			fragColor[2] *= tex.pixels[to+2];
			fragColor[3] *= tex.pixels[to+3];
		}

		color[o+0] = fragColor[0];
		color[o+1] = fragColor[1];
		color[o+2] = fragColor[2];
		color[o+3] = fragColor[3];
	}

	/*
		Draw a line to the specified pixel array.
	*/

	function drawLine( p, color, depth, gl )
	{
		var x0 = Math.floor( p[0][0] );
		var y0 = Math.floor( p[0][1] );
		var x1 = Math.ceil( p[1][0] );
		var y1 = Math.ceil( p[1][1] );
		var dx = Math.abs( x1 - x0 );
		var dy = Math.abs( y1 - y0 );
		var sx = x0 < x1 ? 1 : -1;
		var sy = y0 < y1 ? 1 : -1;
		var err = dx - dy;

		var totDist = dx > dy ? dx : dy;

		while ( true )
		{
			var ic0 = Math.abs( dx > dy ? ( x1 - x0 ) : ( y1 - y0 ) ) / totDist;
			var ic1 = 1.0 - ic0;

			var o = (x0+y0*w)*4;

			var z =  1 / ( ic0*1/p[0][2] + ic1*1/p[1][2] );
			if ( gl.depthEnabled ) {
				if ( z > depth[o/4] ) continue;
				else depth[o/4] = z;
			}

			// Vertex color
			var fragColor = [];
			fragColor[0] = ( ic0*p[0][3][0]/p[0][2] + ic1*p[1][3][0]/p[1][2] ) * z;
			fragColor[1] = ( ic0*p[0][3][1]/p[0][2] + ic1*p[1][3][1]/p[1][2] ) * z;
			fragColor[2] = ( ic0*p[0][3][2]/p[0][2] + ic1*p[1][3][2]/p[1][2] ) * z;
			fragColor[3] = ( ic0*p[0][3][3]/p[0][2] + ic1*p[1][3][3]/p[1][2] ) * z;

			// Texture sample
			var tex = gl.textures[gl.curTexture];
			if ( gl.textureEnabled && tex !== undefined ) {
				var u = ( ic0*p[0][4][0]/p[0][2] + ic1*p[1][4][0]/p[1][2] ) * z;
				var v = ( ic0*p[0][4][1]/p[0][2] + ic1*p[1][4][1]/p[1][2] ) * z;
				u = Math.floor( u * tex.w ) % tex.w; // This behaviour should later depend on GL_TEXTURE_WRAP_S
				v = Math.floor( v * tex.h ) % tex.h;

				var to = (u+v*tex.w)*4;
				fragColor[0] *= tex.pixels[to+0];
				fragColor[1] *= tex.pixels[to+1];
				fragColor[2] *= tex.pixels[to+2];
				fragColor[3] *= tex.pixels[to+3];
			}

			color[o+0] = fragColor[0];
			color[o+1] = fragColor[1];
			color[o+2] = fragColor[2];
			color[o+3] = fragColor[3];

			if ( x0 == x1 && y0 == y1 ) break;

			var e2 = 2*err;
			if ( e2 > -dy ) {
				err -= dy;
				x0 += sx;
			}
			if ( e2 < dx ) {
				err += dx;
				y0 += sy;
			}
		}
	}

	/*
		Draw a triangle to the specified pixel array.
	*/
	
	Math.min = function( a, b, c ) {
		if ( a <= b && a <= c ) return a;
		else if ( b <= a && b <= c ) return b;
		else if ( c <= a && c <= b ) return c;
	};
	
	Math.max = function( a, b, c ) {
		if ( a >= b && a >= c ) return a;
		else if ( b >= a && b >= c ) return b;
		else if ( c >= a && c >= b ) return c;
	};

	function drawTriangle( p, color, depth, gl )
	{
		if ( gl.cullingEnabled && !p[0][5] ) return;

		var x1 = Math.floor( p[0][0] );
		var x2 = Math.floor( p[1][0] );
		var x3 = Math.floor( p[2][0] );
		var y1 = Math.floor( p[0][1] );
		var y2 = Math.floor( p[1][1] );
		var y3 = Math.floor( p[2][1] );

		var minX = Math.min( x1, x2, x3 );
		var minY = Math.min( y1, y2, y3 );
		var maxX = Math.max( x1, x2, x3 );
		var maxY = Math.max( y1, y2, y3 );

		var factor = 1.0 / ( (y2-y3)*(x1-x3) + (x3-x2)*(y1-y3) );

		var o;
		for ( var x = minX; x <= maxX; x++ ) {
			for ( var y = minY; y <= maxY; y++ ) {
				ic0 = ( (y2-y3)*(x-x3)+(x3-x2)*(y-y3) ) * factor;
				if ( ic0 < 0 || ic0 > 1 ) continue;
				ic1 = ( (y3-y1)*(x-x3)+(x1-x3)*(y-y3) ) * factor;
				if ( ic1 < 0 || ic1 > 1 ) continue;
				ic2 = 1.0 - ic0 - ic1;
				if ( ic2 < 0 || ic2 > 1 ) continue;

				o = (x+y*gl.w)*4;

				var z = 1 / ( ic0*1/p[0][2] + ic1*1/p[1][2] + ic2*1/p[2][2] );
				if ( gl.depthEnabled ) {
					if ( z > depth[o/4] ) continue;
					else depth[o/4] = z;
				}

				// Vertex color
				var fragColor = [];
				fragColor[0] = ( ic0*p[0][3][0]/p[0][2] + ic1*p[1][3][0]/p[1][2] + ic2*p[2][3][0]/p[2][2] ) * z;
				fragColor[1] = ( ic0*p[0][3][1]/p[0][2] + ic1*p[1][3][1]/p[1][2] + ic2*p[2][3][1]/p[2][2] ) * z;
				fragColor[2] = ( ic0*p[0][3][2]/p[0][2] + ic1*p[1][3][2]/p[1][2] + ic2*p[2][3][2]/p[2][2] ) * z;
				fragColor[3] = ( ic0*p[0][3][3]/p[0][2] + ic1*p[1][3][3]/p[1][2] + ic2*p[2][3][3]/p[2][2] ) * z;

				// Texture sample
				var tex = gl.textures[gl.curTexture];
				if ( gl.textureEnabled && tex !== undefined ) {
					var u = ( ic0*p[0][4][0]/p[0][2] + ic1*p[1][4][0]/p[1][2] + ic2*p[2][4][0]/p[2][2] ) * z;
					var v = ( ic0*p[0][4][1]/p[0][2] + ic1*p[1][4][1]/p[1][2] + ic2*p[2][4][1]/p[2][2] ) * z;
					u = Math.floor( u * tex.w ) % tex.w; // This behaviour should later depend on GL_TEXTURE_WRAP_S
					v = Math.floor( v * tex.h ) % tex.h;

					var to = (u+v*tex.w)*4;
					fragColor[0] *= tex.pixels[to+0];
					fragColor[1] *= tex.pixels[to+1];
					fragColor[2] *= tex.pixels[to+2];
					fragColor[3] *= tex.pixels[to+3];
				}

				color[o+0] = fragColor[0];
				color[o+1] = fragColor[1];
				color[o+2] = fragColor[2];
				color[o+3] = fragColor[3];
			}
		}
	}

	/*
		Draw a quad to the specified pixel array.
	*/

	function drawQuad( p, color, depth, gl )
	{
		if ( gl.cullingEnabled ) {
			if ( !p[0][5] ) return;
			p[2][5] = true; // Or drawTriangle will think the second triangle making the quad is culled
		}

		drawTriangle( [ p[0], p[1], p[2] ], color, depth, gl );
		drawTriangle( [ p[2], p[3], p[0] ], color, depth, gl );
	}

	/*
		Clamps a value between 0.0 and 1.0.
	*/

	function fclamp( val )
	{
		return val < 0.0 ? 0.0 : ( val > 1.0 ? 1.0 : val );
	}
	
	return GL;
} )();
